<!DOCTYPE html>
<html lang=zh>
<head><meta name="generator" content="Hexo 3.8.0">
  <meta charset="utf-8">
  
  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no, minimal-ui">
  <meta name="renderer" content="webkit">
  <meta http-equiv="Cache-Control" content="no-transform">
  <meta http-equiv="Cache-Control" content="no-siteapp">
  <meta name="apple-mobile-web-app-capable" content="yes">
  <meta name="apple-mobile-web-app-status-bar-style" content="black">
  <meta name="format-detection" content="telephone=no,email=no,adress=no">
  <!-- Color theme for statusbar -->
  <meta name="theme-color" content="#000000">
  <!-- 强制页面在当前窗口以独立页面显示,防止别人在框架里调用页面 -->
  <meta http-equiv="window-target" content="_top">
  
  
  <title>23种经典设计模式(附c++实现代码) | 王竹兴 | Blob</title>
  <meta name="description" content="概述 设计模式，是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。 描述了在软件设计过程中的一些不断重复发生的问题，以及该问题的解决方案。 是解决特定问题的一系列套路，是前辈们的代码设计经验的总结，具有一定的普遍性，可以反复使用。 其目的是为了提高代码的可重用性、代码的可读性和代码的可靠性。   作用  提高思维能力、编程能力和设计能力。 使程序设计更加标准化、代码编制更加工">
<meta name="keywords" content="c&#x2F;c++">
<meta property="og:type" content="article">
<meta property="og:title" content="23种经典设计模式(附c++实现代码)">
<meta property="og:url" content="http://zhulao.gitee.io/blog/2019/03/31/23种经典设计模式(附c++实现代码)/index.html">
<meta property="og:site_name" content="王竹兴 | Blog">
<meta property="og:description" content="概述 设计模式，是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。 描述了在软件设计过程中的一些不断重复发生的问题，以及该问题的解决方案。 是解决特定问题的一系列套路，是前辈们的代码设计经验的总结，具有一定的普遍性，可以反复使用。 其目的是为了提高代码的可重用性、代码的可读性和代码的可靠性。   作用  提高思维能力、编程能力和设计能力。 使程序设计更加标准化、代码编制更加工">
<meta property="og:locale" content="zh-CN">
<meta property="og:updated_time" content="2019-05-16T11:59:33.770Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="23种经典设计模式(附c++实现代码)">
<meta name="twitter:description" content="概述 设计模式，是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。 描述了在软件设计过程中的一些不断重复发生的问题，以及该问题的解决方案。 是解决特定问题的一系列套路，是前辈们的代码设计经验的总结，具有一定的普遍性，可以反复使用。 其目的是为了提高代码的可重用性、代码的可读性和代码的可靠性。   作用  提高思维能力、编程能力和设计能力。 使程序设计更加标准化、代码编制更加工">
  <!-- Canonical links -->
  <link rel="canonical" href="http://zhulao.gitee.io/blog/2019/03/31/23种经典设计模式(附c++实现代码)/index.html">
  
    <link rel="alternate" href="/atom.xml" title="王竹兴 | Blog" type="application/atom+xml">
  
  
    <link rel="icon" href="/favicon.png" type="image/x-icon">
  
  <link rel="stylesheet" href="/blog/css/style.css">
  
  
  
  
</head>


<body class="main-center" itemscope itemtype="http://schema.org/WebPage">
  <header class="header" itemscope itemtype="http://schema.org/WPHeader">
  <div class="slimContent">
    <div class="navbar-header">
      
      
      <div class="profile-block text-center">
        <a id="avatar" href="https://github.com/wzx3" target="_blank">
          <img class="img-circle img-rotate" src="/blog/images/avatar.jpeg" width="200" height="200">
        </a>
        <h2 id="name" class="hidden-xs hidden-sm">王竹兴</h2>
        <h3 id="title" class="hidden-xs hidden-sm hidden-md"></h3>
        <small id="location" class="text-muted hidden-xs hidden-sm"><i class="icon icon-map-marker"></i> XiaMen, China</small>
      </div>
      
      <div class="search" id="search-form-wrap">

    <form class="search-form sidebar-form">
        <div class="input-group">
            <input type="text" class="search-form-input form-control" placeholder="搜索">
            <span class="input-group-btn">
                <button type="submit" class="search-form-submit btn btn-flat" onclick="return false;"><i class="icon icon-search"></i></button>
            </span>
        </div>
    </form>
    <div class="ins-search">
  <div class="ins-search-mask"></div>
  <div class="ins-search-container">
    <div class="ins-input-wrapper">
      <input type="text" class="ins-search-input" placeholder="想要查找什么..." x-webkit-speech>
      <button type="button" class="close ins-close ins-selectable" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
    </div>
    <div class="ins-section-wrapper">
      <div class="ins-section-container"></div>
    </div>
  </div>
</div>


</div>
      <button class="navbar-toggle collapsed" type="button" data-toggle="collapse" data-target="#main-navbar" aria-controls="main-navbar" aria-expanded="false">
        <span class="sr-only">Toggle navigation</span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
      </button>
    </div>
    <nav id="main-navbar" class="collapse navbar-collapse" itemscope itemtype="http://schema.org/SiteNavigationElement" role="navigation">
      <ul class="nav navbar-nav main-nav menu-highlight">
        
        
        <li class="menu-item menu-item-home">
          <a href="/blog/.">
            
            <i class="icon icon-home-fill"></i>
            
            <span class="menu-title">首页</span>
          </a>
        </li>
        
        
        <li class="menu-item menu-item-archives">
          <a href="/blog/archives">
            
            <i class="icon icon-archives-fill"></i>
            
            <span class="menu-title">归档</span>
          </a>
        </li>
        
        
        <li class="menu-item menu-item-categories">
          <a href="/blog/categories">
            
            <i class="icon icon-folder"></i>
            
            <span class="menu-title">分类</span>
          </a>
        </li>
        
        
        <li class="menu-item menu-item-tags">
          <a href="/blog/tags">
            
            <i class="icon icon-tags"></i>
            
            <span class="menu-title">标签</span>
          </a>
        </li>
        
        
        <li class="menu-item menu-item-repository">
          <a href="/blog/repository">
            
            <i class="icon icon-project"></i>
            
            <span class="menu-title">项目</span>
          </a>
        </li>
        
        
        <li class="menu-item menu-item-about">
          <a href="/blog/about">
            
            <i class="icon icon-cup-fill"></i>
            
            <span class="menu-title">关于</span>
          </a>
        </li>
        
      </ul>
      
	
    <ul class="social-links">
    	
        <li><a href="https://github.com/wzx3" target="_blank" title="Github" data-toggle="tooltip" data-placement="top"><i class="icon icon-github"></i></a></li>
        
        <li><a href="/blog/atom.xml" target="_blank" title="Rss" data-toggle="tooltip" data-placement="top"><i class="icon icon-rss"></i></a></li>
        
    </ul>

    </nav>
  </div>
</header>

  
    <aside class="sidebar" itemscope itemtype="http://schema.org/WPSideBar">
  <div class="slimContent">
    
      <div class="widget">
    <h3 class="widget-title">公告</h3>
    <div class="widget-body">
        <div id="board">
            <div class="content">
                <p>人生最快意的事情之一, 就是你比别人牛逼, 然后静静的看别人在你面前装逼。</p>
            </div>
        </div>
    </div>
</div>

    
      
  <div class="widget">
    <h3 class="widget-title">分类</h3>
    <div class="widget-body">
      <ul class="category-list"><li class="category-list-item"><a class="category-list-link" href="/blog/categories/便签/">便签</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/blog/categories/教程/">教程</a><span class="category-list-count">22</span></li><li class="category-list-item"><a class="category-list-link" href="/blog/categories/游记/">游记</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/blog/categories/随笔/">随笔</a><span class="category-list-count">6</span></li></ul>
    </div>
  </div>


    
      
  <div class="widget">
    <h3 class="widget-title">标签云</h3>
    <div class="widget-body tagcloud">
      <a href="/blog/tags/DL/" style="font-size: 13.25px;">DL</a> <a href="/blog/tags/Debug/" style="font-size: 13.5px;">Debug</a> <a href="/blog/tags/Doc/" style="font-size: 13px;">Doc</a> <a href="/blog/tags/Hexo/" style="font-size: 13.25px;">Hexo</a> <a href="/blog/tags/Links/" style="font-size: 13px;">Links</a> <a href="/blog/tags/Linux/" style="font-size: 13.25px;">Linux</a> <a href="/blog/tags/Mac/" style="font-size: 13px;">Mac</a> <a href="/blog/tags/bazel/" style="font-size: 13px;">bazel</a> <a href="/blog/tags/c-c/" style="font-size: 13.75px;">c/c++</a> <a href="/blog/tags/git/" style="font-size: 13px;">git</a> <a href="/blog/tags/rst/" style="font-size: 13px;">rst</a> <a href="/blog/tags/scripts/" style="font-size: 13.75px;">scripts</a> <a href="/blog/tags/ssh/" style="font-size: 13px;">ssh</a> <a href="/blog/tags/国学经典/" style="font-size: 13px;">国学经典</a> <a href="/blog/tags/持续集成/" style="font-size: 13.25px;">持续集成</a> <a href="/blog/tags/科幻小说/" style="font-size: 14px;">科幻小说</a>
    </div>
  </div>

    
      
  <div class="widget">
    <h3 class="widget-title">归档</h3>
    <div class="widget-body">
      <ul class="archive-list"><li class="archive-list-item"><a class="archive-list-link" href="/blog/archives/2019/05/">五月 2019</a><span class="archive-list-count">6</span></li><li class="archive-list-item"><a class="archive-list-link" href="/blog/archives/2019/04/">四月 2019</a><span class="archive-list-count">10</span></li><li class="archive-list-item"><a class="archive-list-link" href="/blog/archives/2019/03/">三月 2019</a><span class="archive-list-count">6</span></li><li class="archive-list-item"><a class="archive-list-link" href="/blog/archives/2019/02/">二月 2019</a><span class="archive-list-count">10</span></li></ul>
    </div>
  </div>


    
      
  <div class="widget">
    <h3 class="widget-title">最新文章</h3>
    <div class="widget-body">
      <ul class="recent-post-list list-unstyled no-thumbnail">
        
          <li>
            
            <div class="item-inner">
              <p class="item-category">
                <a class="category-link" href="/blog/categories/随笔/">随笔</a>
              </p>
              <p class="item-title">
                <a href="/blog/2019/05/26/读论语/" class="title">读论语</a>
              </p>
              <p class="item-date">
                <time datetime="2019-05-26T01:45:07.000Z" itemprop="datePublished">2019-05-26</time>
              </p>
            </div>
          </li>
          
          <li>
            
            <div class="item-inner">
              <p class="item-category">
                <a class="category-link" href="/blog/categories/随笔/">随笔</a>
              </p>
              <p class="item-title">
                <a href="/blog/2019/05/20/读变型战争/" class="title">读变型战争</a>
              </p>
              <p class="item-date">
                <time datetime="2019-05-20T15:51:57.000Z" itemprop="datePublished">2019-05-20</time>
              </p>
            </div>
          </li>
          
          <li>
            
            <div class="item-inner">
              <p class="item-category">
                <a class="category-link" href="/blog/categories/随笔/">随笔</a>
              </p>
              <p class="item-title">
                <a href="/blog/2019/05/20/读星际远征/" class="title">读黑客横行</a>
              </p>
              <p class="item-date">
                <time datetime="2019-05-20T15:40:09.000Z" itemprop="datePublished">2019-05-20</time>
              </p>
            </div>
          </li>
          
          <li>
            
            <div class="item-inner">
              <p class="item-category">
                <a class="category-link" href="/blog/categories/教程/">教程</a>
              </p>
              <p class="item-title">
                <a href="/blog/2019/05/15/代码格式化工具-clang-format/" class="title">代码格式化工具:clang-format</a>
              </p>
              <p class="item-date">
                <time datetime="2019-05-15T14:39:51.000Z" itemprop="datePublished">2019-05-15</time>
              </p>
            </div>
          </li>
          
          <li>
            
            <div class="item-inner">
              <p class="item-category">
                <a class="category-link" href="/blog/categories/教程/">教程</a>
              </p>
              <p class="item-title">
                <a href="/blog/2019/05/12/Linux-疑难杂症/" class="title">Linux 疑难杂症</a>
              </p>
              <p class="item-date">
                <time datetime="2019-05-12T02:50:29.000Z" itemprop="datePublished">2019-05-12</time>
              </p>
            </div>
          </li>
          
      </ul>
    </div>
  </div>
  

    
  </div>
</aside>

  
  
<aside class="sidebar sidebar-toc collapse" id="collapseToc" itemscope itemtype="http://schema.org/WPSideBar">
  <div class="slimContent">
    <nav id="toc" class="article-toc">
      <h3 class="toc-title">文章目录</h3>
      <ol class="toc"><li class="toc-item toc-level-2"><a class="toc-link" href="#7种开发原则"><span class="toc-number">1.</span> <span class="toc-text"> 7种开发原则</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#开闭原则"><span class="toc-number">1.1.</span> <span class="toc-text"> 开闭原则</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#里氏替换原则"><span class="toc-number">1.2.</span> <span class="toc-text"> 里氏替换原则</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#依赖倒置原则"><span class="toc-number">1.3.</span> <span class="toc-text"> 依赖倒置原则</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#单一职责原则"><span class="toc-number">1.4.</span> <span class="toc-text"> 单一职责原则</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#接口隔离原则"><span class="toc-number">1.5.</span> <span class="toc-text"> 接口隔离原则</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#迪米特法则"><span class="toc-number">1.6.</span> <span class="toc-text"> 迪米特法则</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#合成复用原则"><span class="toc-number">1.7.</span> <span class="toc-text"> 合成复用原则</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#23种设计模式"><span class="toc-number">2.</span> <span class="toc-text"> 23种设计模式</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#创建型-单例"><span class="toc-number">2.1.</span> <span class="toc-text"> 创建型 - 单例</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#创建型-原型"><span class="toc-number">2.2.</span> <span class="toc-text"> 创建型 - 原型</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#创建型-工厂方法"><span class="toc-number">2.3.</span> <span class="toc-text"> 创建型 - 工厂方法</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#创建型-抽象工厂"><span class="toc-number">2.4.</span> <span class="toc-text"> 创建型 - 抽象工厂</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#创建型-建造者"><span class="toc-number">2.5.</span> <span class="toc-text"> 创建型 - 建造者</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#结构型-代理"><span class="toc-number">2.6.</span> <span class="toc-text"> 结构型 - 代理</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#结构型-适配器"><span class="toc-number">2.7.</span> <span class="toc-text"> 结构型 - 适配器</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#结构型-桥接"><span class="toc-number">2.8.</span> <span class="toc-text"> 结构型 - 桥接</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#结构型-装饰"><span class="toc-number">2.9.</span> <span class="toc-text"> 结构型 - 装饰</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#结构型-外观"><span class="toc-number">2.10.</span> <span class="toc-text"> 结构型 - 外观</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#结构型-享元"><span class="toc-number">2.11.</span> <span class="toc-text"> 结构型 - 享元</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#结构型-组合"><span class="toc-number">2.12.</span> <span class="toc-text"> 结构型 - 组合</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#行为型-模板方法"><span class="toc-number">2.13.</span> <span class="toc-text"> 行为型 - 模板方法</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#行为型-策略"><span class="toc-number">2.14.</span> <span class="toc-text"> 行为型 - 策略</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#行为型-命令"><span class="toc-number">2.15.</span> <span class="toc-text"> 行为型 - 命令</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#行为型-责任链"><span class="toc-number">2.16.</span> <span class="toc-text"> 行为型 - 责任链</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#行为型-状态"><span class="toc-number">2.17.</span> <span class="toc-text"> 行为型 - 状态</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#行为型-观察者"><span class="toc-number">2.18.</span> <span class="toc-text"> 行为型 - 观察者</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#行为型-中介者"><span class="toc-number">2.19.</span> <span class="toc-text"> 行为型 - 中介者</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#行为型-迭代器"><span class="toc-number">2.20.</span> <span class="toc-text"> 行为型 - 迭代器</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#行为型-访问者"><span class="toc-number">2.21.</span> <span class="toc-text"> 行为型 - 访问者</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#行为型-备忘录"><span class="toc-number">2.22.</span> <span class="toc-text"> 行为型 - 备忘录</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#行为型-解释器"><span class="toc-number">2.23.</span> <span class="toc-text"> 行为型 - 解释器</span></a></li></ol></li></ol>
    </nav>
  </div>
</aside>

<main class="main" role="main">
  <div class="content">
  <article id="post-23种经典设计模式(附c++实现代码)" class="article article-type-post" itemscope itemtype="http://schema.org/BlogPosting">
    
    <div class="article-header">
      
        
  
    <h1 class="article-title" itemprop="name">
      23种经典设计模式(附c++实现代码)
    </h1>
  

      
      <div class="article-meta">
        <span class="article-date">
    <i class="icon icon-calendar-check"></i>
	<a href="/blog/2019/03/31/23种经典设计模式(附c++实现代码)/" class="article-date">
	  <time datetime="2019-03-31T00:39:42.000Z" itemprop="datePublished">2019-03-31</time>
	</a>
</span>
        
  <span class="article-category">
    <i class="icon icon-folder"></i>
    <a class="article-category-link" href="/blog/categories/教程/">教程</a>
  </span>

        
  <span class="article-tag">
    <i class="icon icon-tags"></i>
	<a class="article-tag-link" href="/blog/tags/c-c/">c/c++</a>
  </span>


        
	<span class="article-read hidden-xs">
	    <i class="icon icon-eye-fill" aria-hidden="true"></i>
	    <span id="busuanzi_container_page_pv">
			<span id="busuanzi_value_page_pv">0</span>
		</span>
	</span>


        <span class="post-comment"><i class="icon icon-comment"></i> <a href="/blog/2019/03/31/23种经典设计模式(附c++实现代码)/#comments" class="article-comment-link">评论</a></span>
        
	
		<span class="post-wordcount hidden-xs" itemprop="wordCount">字数统计: 19,823(字)</span>
	
	
		<span class="post-readcount hidden-xs" itemprop="timeRequired">阅读时长: 83(分)</span>
	

      </div>
    </div>
    <div class="article-entry marked-body" itemprop="articleBody">
      
        <ul>
<li>
<p><strong>概述</strong></p>
<p>设计模式，<strong>是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结</strong>。</p>
<p>描述了在软件设计过程中的<strong>一些不断重复发生的问题</strong>，以及该问题的解决方案。</p>
<p>是解决特定问题的一系列套路，是前辈们的代码设计经验的总结，具有一定的普遍性，可以反复使用。</p>
<p>其目的是<strong>为了提高代码的可重用性、代码的可读性和代码的可靠性</strong>。</p>
</li>
<li>
<p><strong>作用</strong></p>
<ul>
<li>提高思维能力、编程能力和设计能力。</li>
<li>使程序<strong>设计更加标准化</strong>、代码编制<strong>更加工程化</strong>，使软件开发效率大大提高，从而<strong>缩短软件的开发周期</strong>。</li>
<li>使设计的代码<strong>可重用性高、可读性强、可靠性高、灵活性好、可维护性强</strong>。</li>
</ul>
</li>
<li>
<p>部分<strong>转载</strong>的原文链接</p>
<ul>
<li><a href="http://c.biancheng.net/view/1317.html" target="_blank" rel="noopener"><strong>软件设计模式概述</strong></a></li>
<li><a href="%5Bhttps://github.com/CyC2018/CS-Notes/blob/master/docs/notes/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F.md%5D(https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F.md)">CS-Notes <strong>设计模式</strong></a></li>
</ul>
</li>
<li>
<p>本文<strong>示例代码</strong></p>
<ul>
<li><a href="https://github.com/wzx3/design-mode" target="_blank" rel="noopener"><strong>design-mode</strong></a></li>
</ul>
</li>
</ul>
<h2 id="7种开发原则"><a class="markdownIt-Anchor" href="#7种开发原则"></a> 7种开发原则</h2>
<h3 id="开闭原则"><a class="markdownIt-Anchor" href="#开闭原则"></a> 开闭原则</h3>
<ul>
<li>
<p>定义</p>
<ul>
<li>
<p><strong><code>Open Closed Principle，OCP</code></strong></p>
</li>
<li>
<p>软件实体应当<strong>对扩展开放，对修改关闭</strong>。即, 当应用的需求改变时，在不修改软件实体的源代码或者二进制代码的前提下，可以扩展模块的功能，使其满足新的需求。</p>
</li>
</ul>
</li>
<li>
<p>作用</p>
<ul>
<li>
<p>对<strong>软件测试</strong>的影响</p>
<p>测试时<strong>只需要对扩展的代码进行测试</strong>就可以了，因为原有的测试代码仍然能够正常运行。</p>
</li>
<li>
<p>提高代码的<strong>可复用</strong>性</p>
<p>粒度越小，被复用的可能性就越大；在面向对象的程序设计中，根据原子和抽象编程可以提高代码的可复用性。</p>
</li>
<li>
<p>提高软件的<strong>可维护</strong>性</p>
<p>稳定性高和延续性强，从而易于扩展和维护。</p>
</li>
</ul>
</li>
</ul>
<h3 id="里氏替换原则"><a class="markdownIt-Anchor" href="#里氏替换原则"></a> 里氏替换原则</h3>
<ul>
<li>
<p>定义</p>
<ul>
<li>
<p><code>Liskov Substitution Principle，LSP</code></p>
</li>
<li>
<p><strong>继承必须确保基类所拥有的性质在子类中仍然成立</strong>。即, 子类可以扩展父类的功能，但不能改变父类原有的功能。</p>
</li>
</ul>
</li>
<li>
<p>作用</p>
<ul>
<li>是实现开闭原则的重要方式之一。</li>
<li>克服了继承中重写父类造成的可复用性变差的缺点。</li>
<li>类的扩展不会给已有的系统引入新的错误，降低了代码出错的可能性。</li>
</ul>
</li>
</ul>
<h3 id="依赖倒置原则"><a class="markdownIt-Anchor" href="#依赖倒置原则"></a> 依赖倒置原则</h3>
<ul>
<li>
<p>定义</p>
<ul>
<li>
<p><code>Dependence Inversion Principle，DIP</code></p>
</li>
<li>
<p>**要面向接口编程，不要面向实现编程。**即, 高层模块不应该依赖低层模块，两者都应该依赖其抽象；抽象不应该依赖细节，细节应该依赖抽象。</p>
</li>
</ul>
</li>
<li>
<p>作用</p>
<ul>
<li>可以<strong>降低类间的耦合性</strong>。</li>
<li>可以减少并行开发引起的风险。</li>
<li>可以<strong>提高代码的可读性</strong>和可维护性。</li>
</ul>
</li>
</ul>
<h3 id="单一职责原则"><a class="markdownIt-Anchor" href="#单一职责原则"></a> 单一职责原则</h3>
<ul>
<li>定义
<ul>
<li><code>Single Responsibility Principle，SRP</code></li>
<li>单一职责原则规定<strong>一个类应该有且仅有一个引起它变化的原因</strong>，否则类应该被拆分。</li>
<li>如果一个对象承担了太多的职责，至少存在以下两个缺点
<ul>
<li>一个职责的变化可能会削弱或者抑制这个类实现其他职责的能力；</li>
<li><strong>当客户端需要该对象的某一个职责时，不得不将其他不需要的职责全都包含进来，从而造成冗余代码</strong>或代码的浪费。</li>
</ul>
</li>
</ul>
</li>
<li>作用
<ul>
<li>降低类的复杂度。一个类只负责一项职责，其逻辑肯定要比负责多项职责简单得多。</li>
<li><strong>提高类的可读性</strong>。复杂性降低，自然其可读性会提高。</li>
<li>提高系统的可维护性。可读性提高，那自然更容易维护了。</li>
<li>变更引起的风险降低。变更是必然的，如果单一职责原则遵守得好，当修改一个功能时，可以显著降低对其他功能的影响。</li>
</ul>
</li>
</ul>
<h3 id="接口隔离原则"><a class="markdownIt-Anchor" href="#接口隔离原则"></a> 接口隔离原则</h3>
<ul>
<li>定义
<ul>
<li><code>Interface Segregation Principle，ISP</code></li>
<li><strong>客户端不应该被迫依赖于它不使用的方法</strong></li>
<li><strong>一个类对另一个类的依赖应该建立在最小的接口上</strong></li>
<li>与单一职责原则的区别
<ul>
<li>单一职责原则注重的是职责，而接口隔离原则注重的是对接口依赖的隔离。</li>
<li>单一职责原则主要是约束类，它针对的是程序中的实现和细节；接口隔离原则主要约束接口，主要针对抽象和程序整体框架的构建。</li>
</ul>
</li>
</ul>
</li>
<li>作用
<ul>
<li><strong>将臃肿庞大的接口分解为多个粒度小的接口</strong>，可以预防外来变更的扩散，提高系统的灵活性和可维护性。</li>
<li>接口隔离提高了系统的内聚性，<strong>减少了对外交互</strong>，降低了系统的耦合性。</li>
<li>使用多个专门的接口还能够体现对象的层次，因为可以通过接口的继承，实现对总接口的定义。</li>
<li>能<strong>减少项目工程中的代码冗余</strong>。过大的大接口里面通常放置许多不用的方法，当实现这个接口的时候，被迫设计冗余的代码。</li>
</ul>
</li>
</ul>
<h3 id="迪米特法则"><a class="markdownIt-Anchor" href="#迪米特法则"></a> 迪米特法则</h3>
<ul>
<li>定义
<ul>
<li><code>Law of Demeter，LoD</code>, 又叫作<strong>最少知识原则</strong>（<code>Least Knowledge Principle，LKP</code>)</li>
<li><strong>如果两个软件实体无须直接通信，那么就不应当发生直接的相互调用</strong>，可以通过第三方转发该调用。其目的是降低类之间的耦合度，提高模块的相对独立性。</li>
</ul>
</li>
<li>作用
<ul>
<li>降低了类之间的耦合度，提高了模块的相对独立性。</li>
<li>由于亲合度降低，从而提高了类的可复用率和系统的扩展性。</li>
</ul>
</li>
</ul>
<h3 id="合成复用原则"><a class="markdownIt-Anchor" href="#合成复用原则"></a> 合成复用原则</h3>
<ul>
<li>
<p>定义</p>
<ul>
<li><code>Composite Reuse Principle，CRP</code>, 又叫<strong>组合/聚合复用原则</strong>（<code>Composition/Aggregate Reuse Principle，CARP</code>）。</li>
<li>在软件复用时，要尽量<strong>先使用组合或者聚合等关联关系</strong>来实现，其次才考虑使用继承关系来实现。</li>
</ul>
</li>
<li>
<p>作用</p>
<ul>
<li>
<p>通常类的复用分为<strong>继承复用</strong>和<strong>合成复用</strong>两种，继承复用虽然有简单和易实现的优点，但它也存在以下缺点:</p>
<ul>
<li>
<p><strong>继承复用破坏了类的封装性</strong>。因为继承会将父类的实现细节暴露给子类，父类对子类是透明的，所以这种复用又称为“白箱”复用。</p>
</li>
<li>
<p><strong>子类与父类的耦合度高。父类的实现的任何改变都会导致子类的实现发生变化</strong>，这不利于类的扩展与维护。</p>
</li>
<li>
<p>它<strong>限制了复用的灵活性。从父类继承而来的实现是静态的，在编译时已经定义，所以在运行时不可能发生变化。</strong></p>
</li>
</ul>
</li>
<li>
<p>采用组合或聚合复用时，可以<strong>将已有对象纳入新对象中，使之成为新对象的一部分，新对象可以调用已有对象的功能</strong>，它有以下优点:</p>
<ul>
<li>
<p>它维持了类的封装性。因为<strong>成分对象的内部细节是新对象看不见的</strong>，所以这种复用又称为“黑箱”复用。</p>
</li>
<li>
<p>新旧类之间的耦合度低。这种复用所需的依赖较少，<strong>新对象存取成分对象的唯一方法是通过成分对象的接口</strong>。</p>
</li>
<li>
<p>复用的灵活性高。这种复用可以在运行时动态进行，新对象可以动态地引用与成分对象类型相同的对象。</p>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<h2 id="23种设计模式"><a class="markdownIt-Anchor" href="#23种设计模式"></a> 23种设计模式</h2>
<blockquote>
<p><a href="http://c.biancheng.net/design_pattern/" target="_blank" rel="noopener">设计模式</a>有两种分类方法，即根据模式的目的来分和根据模式的作用的范围来分。</p>
</blockquote>
<ul>
<li>
<p><strong>根据目的来分</strong></p>
<ul>
<li><code>创建型模式</code>：用于描述“怎样创建对象”，它的主要特点是“<strong>将对象的创建与使用分离</strong>”。 如, 单例、原型、工厂方法、抽象工厂、建造者等 5 种。</li>
<li><code>结构型模式</code>：用于描述如何将类或对象<strong>按某种布局组成更大的结构</strong>。 如, 代理、适配器、桥接、装饰、外观、享元、组合等 7 种。</li>
<li><code>行为型模式</code>：用于描述<strong>类或对象之间怎样相互协作</strong>共同完成单个对象都无法单独完成的任务，以及怎样分配职责。如, 模板方法、策略、命令、责任链、状态、观察者、中介者、迭代器、访问者、备忘录、解释器等 11 种。</li>
</ul>
</li>
<li>
<p><strong>根据作用范围来分</strong></p>
<ul>
<li><code>类模式</code>：用于处理类与子类之间的关系，这些关系<strong>通过继承来建立</strong>，是静态的，在<strong>编译时刻便确定</strong>下来了。如, 工厂方法、（类）适配器、模板方法、解释器属于该模式。</li>
<li><code>对象模式</code>：用于处理对象之间的关系，这些关系可以<strong>通过组合或聚合来实现</strong>，在<strong>运行时刻是可以变化</strong>的，更具动态性。除了以上 4 种，其他的都是对象模式。</li>
</ul>
</li>
</ul>
<h3 id="创建型-单例"><a class="markdownIt-Anchor" href="#创建型-单例"></a> 创建型 - 单例</h3>
<ul>
<li>
<p>含义</p>
<p><code>Singleton</code> 确保<strong>一个类只有一个实例</strong>，并提供该实例的全局访问点。</p>
</li>
<li>
<p>实现方式</p>
<ul>
<li>使用<strong>一个私有构造函数</strong>、<strong>一个私有静态变量</strong>以及<strong>一个公有静态函数</strong>来实现。</li>
<li>私有构造函数保证了不能通过构造函数来创建对象实例，只能通过公有静态函数返回唯一的私有静态变量。</li>
</ul>
</li>
<li>
<p>应用场景</p>
<ul>
<li>某类<strong>只要求生成一个对象</strong>的时候，如一个班中的班长、每个人的身份证号等。</li>
<li><strong>当对象需要被共享</strong>的场合。由于单例模式只允许创建一个对象，共享该对象可以节省内存，并加快对象访问速度。如 Web 中的配置对象、数据库的连接池等。</li>
<li><strong>当某类需要频繁实例化</strong>，而创建的对象又频繁被销毁的时候，如多线程的线程池、网络连接池等。</li>
</ul>
</li>
<li>
<p>示例</p>
<ul>
<li>
<p><strong>懒汉式</strong></p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">pragma</span> once</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;mutex&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> singleton &#123;</span><br><span class="line">    </span><br><span class="line"><span class="comment">/// @brief 懒汉式单例. 类加载时没有生成单例, 第一次调用 getInstance 方法时才去创建</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">LazySingleton</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function">LazySingleton* <span class="title">getInstance</span><span class="params">()</span> </span>&#123; </span><br><span class="line">        <span class="keyword">if</span> (!instance_) &#123;</span><br><span class="line">            <span class="built_in">std</span>::unique_lock&lt;<span class="built_in">std</span>::mutex&gt; lock(mutex_);</span><br><span class="line">            <span class="keyword">if</span> (!instance_) instance_ = <span class="keyword">new</span> LazySingleton();    <span class="comment">// 可能出现两个线程都执行了第一次 if 语句</span></span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> instance_; </span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line">    LazySingleton() &#123;&#125;</span><br><span class="line">    <span class="keyword">static</span> LazySingleton* instance_;</span><br><span class="line">    <span class="keyword">static</span> <span class="built_in">std</span>::mutex mutex_;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">LazySingleton* LazySingleton::instance_ = <span class="literal">nullptr</span>;</span><br><span class="line"></span><br><span class="line">&#125; <span class="comment">// namespace singleton</span></span><br></pre></td></tr></table></figure>
</li>
<li>
<p><strong>饿汉式</strong></p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">pragma</span> once</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> singleton &#123;</span><br><span class="line">    </span><br><span class="line"><span class="comment">/// @brief 饿汉式单例. 类一旦加载就创建一个单例</span></span><br><span class="line"><span class="comment">/// 优点: 线程安全</span></span><br><span class="line"><span class="comment">/// 缺点: 丢失延迟实例化带来的节约资源的好处</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">HungrySingleton</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function">HungrySingleton* <span class="title">getInstance</span><span class="params">()</span> </span>&#123; <span class="keyword">return</span> instance_; &#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line">    HungrySingleton() &#123;&#125;</span><br><span class="line">    <span class="keyword">static</span> HungrySingleton* instance_;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">HungrySingleton* HungrySingleton::instance_ = <span class="keyword">new</span> HungrySingleton();</span><br><span class="line"></span><br><span class="line">&#125; <span class="comment">// namespace singleton</span></span><br></pre></td></tr></table></figure>
</li>
</ul>
</li>
<li>
<p>扩展</p>
<ul>
<li>可扩展为<strong>有限的多例（<code>Multitcm</code>）模式</strong>，这种模式可生成有限个实例并保存在 ArmyList 中，客户需要时可随机获取</li>
</ul>
</li>
</ul>
<h3 id="创建型-原型"><a class="markdownIt-Anchor" href="#创建型-原型"></a> 创建型 - 原型</h3>
<ul>
<li>
<p>含义</p>
<p><code>Prototype</code> 将一个对象作为原型，通过对其进行复制而克隆出多个和原型类似的新实例。</p>
<p>复制一个对象分为浅拷贝和深拷贝:</p>
<ul>
<li><strong>浅拷贝</strong>: 给对象中的每个成员变量进行复制，就是把A1类中的变量直接赋给A2类中变量，属于<strong>值传递</strong>，但是涉及到有new之类内存分配的地方，他们却是<strong>共享内存</strong>的。[默认]</li>
<li><strong>深拷贝</strong>: 不仅使用值传递，而是要每个变量都有自己一份独立的内存空间，互不干扰。</li>
</ul>
</li>
<li>
<p>应用场景</p>
<ul>
<li>对象之间相同或相似，即只是个别的几个属性不同的时候。</li>
<li>对象的创建过程比较麻烦，但复制比较简单的时候。</li>
</ul>
</li>
<li>
<p>示例</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">pragma</span> once</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdio.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> prototype &#123;</span><br><span class="line">    </span><br><span class="line"><span class="comment">/// @brief 需要从A的实例得到一份与A内容相同，但是又互不干扰的实例</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/// @brief 抽象原型类</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">AbstractPrototype</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    AbstractPrototype() = <span class="keyword">default</span>;</span><br><span class="line">	<span class="keyword">virtual</span> ~AbstractPrototype() &#123;&#125;</span><br><span class="line"></span><br><span class="line">	<span class="function"><span class="keyword">virtual</span> AbstractPrototype* <span class="title">clone</span><span class="params">()</span> </span>= <span class="number">0</span>;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">/// @brief 具体原型类</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">ConcretePrototype</span> :</span> <span class="keyword">public</span> AbstractPrototype &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">	ConcretePrototype() = <span class="keyword">default</span>;</span><br><span class="line">	~ConcretePrototype() &#123;&#125;</span><br><span class="line"></span><br><span class="line">	<span class="function">AbstractPrototype* <span class="title">clone</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> ConcretePrototype(*<span class="keyword">this</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line">	ConcretePrototype(<span class="keyword">const</span> ConcretePrototype&amp; other) &#123;</span><br><span class="line">        <span class="built_in">fprintf</span>(<span class="built_in">stderr</span>, <span class="string">"ConcretePrototype copy construct!\n"</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">&#125; <span class="comment">// namespace prototype</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">Test_02_prototype_impl_1</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">"-------------------- %s --------------------\n"</span>, __FUNCTION__);</span><br><span class="line">    prototype::AbstractPrototype* ptr_a = <span class="keyword">new</span> prototype::ConcretePrototype();</span><br><span class="line">    prototype::AbstractPrototype* ptr_b = ptr_a-&gt;clone();</span><br><span class="line"></span><br><span class="line">    <span class="keyword">delete</span> ptr_a;</span><br><span class="line">    <span class="keyword">delete</span> ptr_b; </span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// -------------------- Test_02_prototype_impl_1 --------------------</span></span><br><span class="line"><span class="comment">// ConcretePrototype copy construct!</span></span><br></pre></td></tr></table></figure>
</li>
</ul>
<h3 id="创建型-工厂方法"><a class="markdownIt-Anchor" href="#创建型-工厂方法"></a> 创建型 - 工厂方法</h3>
<ul>
<li>
<p>含义</p>
<p><code>Factory Method</code> 定义一个用于创建产品的接口，由子类决定生产什么产品。</p>
<ul>
<li>优点:
<ul>
<li>用户只需要知道具体工厂的名称就可得到所要的产品，无须知道产品的具体创建过程；</li>
<li>在系统增加新的产品时只需要添加具体产品类和对应的具体工厂类，无须对原工厂进行任何修改，<strong>满足开闭原则</strong>；</li>
</ul>
</li>
<li>缺点:
<ul>
<li>每增加一个产品就要增加一个具体产品类和一个对应的具体工厂类，这增加了系统的复杂度。</li>
</ul>
</li>
</ul>
</li>
<li>
<p>应用场景</p>
<ul>
<li>客户只知道创建产品的工厂名，而不知道具体的产品名。</li>
<li>创建对象的任务由多个具体子工厂中的某一个完成，而抽象工厂只提供创建产品的接口。</li>
<li>客户不关心创建产品的细节，只关心产品的品牌。</li>
</ul>
</li>
<li>
<p>扩展</p>
<ul>
<li>当需要生成的产品不多且不会增加，一个具体工厂类就可以完成任务时，可删除抽象工厂类。这时工厂方法模式将退化到<strong>简单工厂模式</strong>。</li>
</ul>
</li>
<li>
<p>示例</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">pragma</span> once</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdio.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> factory &#123;</span><br><span class="line">    </span><br><span class="line"><span class="comment">/// @brief 抽象产品 - 定义了产品的规范，描述了产品的主要特性和功能</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">AbstractProduct</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="keyword">virtual</span> ~AbstractProduct() &#123;&#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Show</span><span class="params">()</span> </span>= <span class="number">0</span>;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">/// @brief 具体产品 - 实现了抽象产品角色所定义的接口，由具体工厂来创建，它同具体工厂之间一一对应</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">ConcreteProduct</span> :</span> <span class="keyword">public</span> AbstractProduct &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Show</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">"ConcreteProduct Show ...\n"</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">/// @brief 抽象工厂 - 提供了创建产品的接口</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">AbstractFactory</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="keyword">virtual</span> ~AbstractFactory() &#123;&#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> AbstractProduct* <span class="title">CreateProduct</span><span class="params">()</span> </span>= <span class="number">0</span>;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">/// @brief 具体工厂 - 实现抽象工厂中的抽象方法，完成具体产品的创建</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">ConcreteFactory</span> :</span> <span class="keyword">public</span> AbstractFactory &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> AbstractProduct* <span class="title">CreateProduct</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        AbstractProduct* ptr = <span class="keyword">new</span> ConcreteProduct();</span><br><span class="line">        <span class="keyword">return</span> ptr;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">&#125; <span class="comment">// namespace factory </span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">Test_03_factory_impl_1</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">"-------------------- %s --------------------\n"</span>, __FUNCTION__);</span><br><span class="line">    factory::AbstractFactory* ptr_factory = <span class="keyword">new</span> factory::ConcreteFactory();</span><br><span class="line">    factory::AbstractProduct* ptr_product = ptr_factory-&gt;CreateProduct();</span><br><span class="line">    ptr_product-&gt;Show();</span><br><span class="line">    <span class="keyword">delete</span> ptr_factory;</span><br><span class="line">    <span class="keyword">delete</span> ptr_product;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// -------------------- Test_03_factory_impl_1 --------------------</span></span><br><span class="line"><span class="comment">// ConcreteProduct Show ...</span></span><br></pre></td></tr></table></figure>
</li>
</ul>
<h3 id="创建型-抽象工厂"><a class="markdownIt-Anchor" href="#创建型-抽象工厂"></a> 创建型 - 抽象工厂</h3>
<ul>
<li>
<p>含义</p>
<p><code>AbstractFactory</code> 为访问类提供一个创建一组相关或相互依赖对象的接口，且<strong>访问类无须指定所要产品的具体类</strong>就能得到同族的不同等级的产品的模式结构。</p>
<p><strong>抽象工厂模式是工厂方法模式的升级版本</strong>，工厂方法模式只生产一个等级的产品，而抽象工厂模式可生产多个等级的产品。</p>
<ul>
<li>优点
<ul>
<li>可以在类的内部对产品族中相关联的<strong>多等级产品共同管理</strong>，而不必专门引入多个新的类来进行管理。</li>
<li>当<strong>增加一个新的产品族时不需要修改原代码，满足开闭原则</strong>。</li>
</ul>
</li>
<li>缺点
<ul>
<li><strong>当产品族中需要增加一个新的产品时，所有的工厂类都需要进行修改。</strong></li>
</ul>
</li>
</ul>
</li>
<li>
<p>示例</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">pragma</span> once</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdio.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> abstract_factory &#123;</span><br><span class="line">    </span><br><span class="line"><span class="comment">/// @brief 抽象产品 - 定义了产品的规范，描述了产品的主要特性和功能</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">AbstractProductA</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="keyword">virtual</span> ~AbstractProductA() &#123;&#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Show</span><span class="params">()</span> </span>= <span class="number">0</span>;</span><br><span class="line">&#125;;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">AbstractProductB</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="keyword">virtual</span> ~AbstractProductB() &#123;&#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Show</span><span class="params">()</span> </span>= <span class="number">0</span>;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">/// @brief 具体产品 - 实现了抽象产品角色所定义的接口，由具体工厂来创建，它同具体工厂之间一一对应</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">ConcreteProductA1</span> :</span> <span class="keyword">public</span> AbstractProductA &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Show</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">"ConcreteProductA1 Show ...\n"</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">ConcreteProductA2</span> :</span> <span class="keyword">public</span> AbstractProductA &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Show</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">"ConcreteProductA2 Show ...\n"</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">ConcreteProductB1</span> :</span> <span class="keyword">public</span> AbstractProductB &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Show</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">"ConcreteProductB1 Show ...\n"</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">ConcreteProductB2</span> :</span> <span class="keyword">public</span> AbstractProductB &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Show</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">"ConcreteProductB2 Show ...\n"</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">/// @brief 抽象工厂 - 提供了创建产品的接口</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">AbstractFactory</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="keyword">virtual</span> ~AbstractFactory() &#123;&#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> AbstractProductA* <span class="title">CreateProductA</span><span class="params">()</span> </span>= <span class="number">0</span>;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> AbstractProductB* <span class="title">CreateProductB</span><span class="params">()</span> </span>= <span class="number">0</span>;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">/// @brief 具体工厂 - 实现抽象工厂中的抽象方法，完成具体产品的创建</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">ConcreteFactory1</span> :</span> <span class="keyword">public</span> AbstractFactory &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> AbstractProductA* <span class="title">CreateProductA</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        AbstractProductA* ptr = <span class="keyword">new</span> ConcreteProductA1();</span><br><span class="line">        <span class="keyword">return</span> ptr;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> AbstractProductB* <span class="title">CreateProductB</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        AbstractProductB* ptr = <span class="keyword">new</span> ConcreteProductB1();</span><br><span class="line">        <span class="keyword">return</span> ptr;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">ConcreteFactory2</span> :</span> <span class="keyword">public</span> AbstractFactory &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> AbstractProductA* <span class="title">CreateProductA</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        AbstractProductA* ptr = <span class="keyword">new</span> ConcreteProductA2();</span><br><span class="line">        <span class="keyword">return</span> ptr;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> AbstractProductB* <span class="title">CreateProductB</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        AbstractProductB* ptr = <span class="keyword">new</span> ConcreteProductB2();</span><br><span class="line">        <span class="keyword">return</span> ptr;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">&#125; <span class="comment">// namespace abstract_factory</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">Test_04_abstract_factory_impl_1</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">"-------------------- %s --------------------\n"</span>, __FUNCTION__);</span><br><span class="line">    abstract_factory::AbstractFactory* ptr_factory_1 = <span class="keyword">new</span> abstract_factory::ConcreteFactory1();</span><br><span class="line">    abstract_factory::AbstractProductA* ptr_product_A1 = ptr_factory_1-&gt;CreateProductA();</span><br><span class="line">    ptr_product_A1-&gt;Show();</span><br><span class="line">    <span class="keyword">delete</span> ptr_factory_1;</span><br><span class="line">    <span class="keyword">delete</span> ptr_product_A1;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// -------------------- Test_04_abstract_factory_impl_1 --------------------</span></span><br><span class="line"><span class="comment">// ConcreteProductA1 Show ...</span></span><br></pre></td></tr></table></figure>
</li>
</ul>
<h3 id="创建型-建造者"><a class="markdownIt-Anchor" href="#创建型-建造者"></a> 创建型 - 建造者</h3>
<ul>
<li>
<p>含义</p>
<p><code>Builder</code> 将一个复杂对象分解成多个相对简单的部分，然后根据不同需要分别创建它们，最后构建成该复杂对象。</p>
<ul>
<li>优点
<ul>
<li><strong>各个具体的建造者相互独立</strong>，有利于系统的扩展。</li>
<li><strong>客户端不必知道产品内部组成的细节</strong>，便于控制细节风险。</li>
</ul>
</li>
<li>缺点
<ul>
<li><strong>产品的组成部分必须相同</strong>，这限制了其使用范围。</li>
<li>如果产品的内部变化复杂，该模式会增加很多的建造者类。</li>
</ul>
</li>
</ul>
<p><strong>建造者模式注重零部件的组装过程，而工厂方法模式更注重零部件的创建过程。</strong></p>
</li>
<li>
<p>应用场景</p>
<ul>
<li><strong>创建的对象较复杂</strong>，由多个部件构成，各部件面临着复杂的变化，但构件间的建造顺序是稳定的。</li>
<li><strong>创建复杂对象的算法独立于该对象的组成部分以及它们的装配方式</strong>，即产品的构建过程和最终的表示是独立的。</li>
</ul>
</li>
<li>
<p>示例</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">pragma</span> once</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;string&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> builder &#123;</span><br><span class="line">    </span><br><span class="line"><span class="comment">/// @brief 产品 - 包含多个组成部件的复杂对象。</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Product</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">Show</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">"Show Product ...\n"</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line">    <span class="built_in">std</span>::<span class="built_in">string</span> partA_;</span><br><span class="line">    <span class="built_in">std</span>::<span class="built_in">string</span> partB_;</span><br><span class="line">    <span class="built_in">std</span>::<span class="built_in">string</span> partC_;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">/// @brief 抽象建造者 - 包含创建产品各个子部件的抽象方法</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">AbstractBuilder</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    AbstractBuilder() &#123;</span><br><span class="line">        product_.reset(<span class="keyword">new</span> Product());</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function">Product* <span class="title">GetResult</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> product_.get();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">BuilderPartA</span><span class="params">()</span> </span>= <span class="number">0</span>;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">BuilderPartB</span><span class="params">()</span> </span>= <span class="number">0</span>;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">BuilderPartC</span><span class="params">()</span> </span>= <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">protected</span>:</span><br><span class="line">    <span class="built_in">std</span>::<span class="built_in">shared_ptr</span>&lt;Product&gt; product_;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">/// @brief 具体建造者 - 实现了抽象建造者接口</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">ConcreteBuilder</span> :</span> <span class="keyword">public</span> AbstractBuilder &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">BuilderPartA</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">"Builder PartA...\n"</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">BuilderPartB</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">"Builder PartB...\n"</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">BuilderPartC</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">"Builder PartC...\n"</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">/// @brief 指挥者 - 调用建造者中的方法完成复杂对象的创建</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Director</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    Director(AbstractBuilder* builder) : builder_(builder) &#123;&#125;</span><br><span class="line">    <span class="function">Product* <span class="title">ConstructProduct</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        builder_-&gt;BuilderPartA();</span><br><span class="line">        builder_-&gt;BuilderPartB();</span><br><span class="line">        builder_-&gt;BuilderPartC();</span><br><span class="line">        <span class="keyword">return</span> builder_-&gt;GetResult();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line">    AbstractBuilder* builder_;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">&#125; <span class="comment">// namespace builder</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">Test_05_builder_impl_1</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">"-------------------- %s --------------------\n"</span>, __FUNCTION__);</span><br><span class="line">    <span class="built_in">std</span>::<span class="built_in">shared_ptr</span>&lt;builder::AbstractBuilder&gt; builder(<span class="keyword">new</span> builder::ConcreteBuilder());</span><br><span class="line">    <span class="built_in">std</span>::<span class="built_in">shared_ptr</span>&lt;builder::Director&gt; director(<span class="keyword">new</span> builder::Director(builder.get()));</span><br><span class="line"></span><br><span class="line">    builder::Product* ptr = director-&gt;ConstructProduct();</span><br><span class="line">    ptr-&gt;Show();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// -------------------- Test_05_builder_impl_1 --------------------</span></span><br><span class="line"><span class="comment">// Builder PartA...</span></span><br><span class="line"><span class="comment">// Builder PartB...</span></span><br><span class="line"><span class="comment">// Builder PartC...</span></span><br><span class="line"><span class="comment">// Show Product ...</span></span><br></pre></td></tr></table></figure>
</li>
</ul>
<h3 id="结构型-代理"><a class="markdownIt-Anchor" href="#结构型-代理"></a> 结构型 - 代理</h3>
<ul>
<li>
<p>含义</p>
<p><code>Proxy</code> 为某对象提供一种代理以控制对该对象的访问。即<strong>控制对其它对象的访问。</strong></p>
<ul>
<li>优点
<ul>
<li>在客户端与目标对象之间<strong>起到一个中介作用和保护目标对象的作用</strong>；</li>
<li><strong>可以扩展目标对象的功能</strong>；</li>
<li>能将客户端与目标对象分离，在一定程度上<strong>降低了系统的耦合度</strong>；</li>
</ul>
</li>
<li>缺点
<ul>
<li>在客户端和目标对象之间增加一个代理对象，会造成请求处理速度变慢；</li>
<li>增加了系统的复杂度；</li>
</ul>
</li>
</ul>
</li>
<li>
<p>应用场景</p>
<ul>
<li>在有些情况下，一个客户不能或者不想直接访问另一个对象，这时需要找一个中介帮忙完成某项任务，这个中介就是代理对象。例如，购买火车票不一定要去火车站买，可以通过 12306 网站或者去火车票代售点买。又如找女朋友、找保姆、找工作等都可以通过找中介完成。</li>
<li>在软件设计中，使用代理模式的例子也很多，例如，要访问的远程对象比较大（如视频或大图像等），其下载要花很多时间。还有因为安全原因需要屏蔽客户端直接访问真实对象，如某单位的内部数据库等。</li>
</ul>
</li>
<li>
<p>示例</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">pragma</span> once</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdio.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> proxy &#123;</span><br><span class="line">    </span><br><span class="line"><span class="comment">/// @brief 抽象主题类, 用于声明真实主题和代理对象实现的业务方法</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">AbstractSubject</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="keyword">virtual</span> ~AbstractSubject() &#123;&#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Request</span><span class="params">()</span> </span>= <span class="number">0</span>;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">/// @breif 真实主题类, 实现了抽象主题中的具体业务，是代理对象所代表的真实对象，是最终要引用的对象</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">RealSubject</span> :</span> <span class="keyword">public</span> AbstractSubject &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Request</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">"this is RealSubject::Request!\n"</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">// @breif 代理类, 提供了与真实主题相同的接口，其内部含有对真实主题的引用，它可以访问、控制或扩展真实主题的功能</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">SubjectProxy</span> :</span> <span class="keyword">public</span> AbstractSubject &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="keyword">virtual</span> ~SubjectProxy() &#123;</span><br><span class="line">        <span class="keyword">if</span> (real_) <span class="keyword">delete</span> real_; </span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Request</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (!real_) real_ = <span class="keyword">new</span> RealSubject();</span><br><span class="line">        PreRequest();</span><br><span class="line">        real_-&gt;Request();</span><br><span class="line">        PostRequest();</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">PreRequest</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">"this is SubjectProxy::PreRequest!\n"</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">PostRequest</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">"this is SubjectProxy::PostRequest!\n"</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line">    RealSubject* real_;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">&#125; <span class="comment">// namespace proxy</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">Test_06_proxy_impl_1</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">"-------------------- %s --------------------\n"</span>, __FUNCTION__);</span><br><span class="line">    proxy::AbstractSubject* ptr = <span class="keyword">new</span> proxy::SubjectProxy();</span><br><span class="line">    ptr-&gt;Request();</span><br><span class="line">    <span class="keyword">delete</span> ptr;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// -------------------- Test_06_proxy_impl_1 --------------------</span></span><br><span class="line"><span class="comment">// this is SubjectProxy::PreRequest!</span></span><br><span class="line"><span class="comment">// this is RealSubject::Request!</span></span><br><span class="line"><span class="comment">// this is SubjectProxy::PostRequest!</span></span><br></pre></td></tr></table></figure>
</li>
</ul>
<h3 id="结构型-适配器"><a class="markdownIt-Anchor" href="#结构型-适配器"></a> 结构型 - 适配器</h3>
<ul>
<li>
<p>含义</p>
<p><code>Adapter</code> <strong>将一个类的接口转换成客户希望的另外一个接口</strong>，使得原本由于接口不兼容而不能一起工作的那些类能一起工作。</p>
<ul>
<li>优点
<ul>
<li>客户端通过适配器可以透明地调用目标接口。</li>
<li>复用了现存的类，程序员不需要修改原有代码而重用现有的适配者类。</li>
<li>将目标类和适配者类解耦，解决了目标类和适配者类接口不一致的问题。</li>
</ul>
</li>
<li>缺点
<ul>
<li>对类适配器来说，更换适配器的实现过程比较复杂。</li>
</ul>
</li>
</ul>
</li>
<li>
<p>应用场景</p>
<ul>
<li>在现实生活中，<strong>经常出现两个对象因接口不兼容而不能在一起工作的实例，这时需要第三者进行适配</strong>。例如，讲中文的人同讲英文的人对话时需要一个翻译，用直流电的笔记本电脑接交流电源时需要一个电源适配器，用计算机访问照相机的 SD 内存卡时需要一个读卡器等。</li>
<li>在软件设计中也可能出现：<strong>需要开发的具有某种业务功能的组件在现有的组件库中已经存在，但它们与当前系统的接口规范不兼容，如果重新开发这些组件成本又很高</strong>，这时用适配器模式能很好地解决这些问题。</li>
</ul>
</li>
<li>
<p>示例</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">pragma</span> once</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdio.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> adapter &#123;</span><br><span class="line">    </span><br><span class="line"><span class="comment">/// @brief 目标接口, 即当前系统业务所期待的接口</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">AbstractTarget</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="keyword">virtual</span> ~AbstractTarget() &#123;&#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Request</span><span class="params">()</span> </span>= <span class="number">0</span>;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">/// @brief 被适配者</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Adaptee</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">SpecificRequest</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">"this is Adaptee::SpecificRequest!\n"</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">/// @brief 适配器, 把适被配者接口转换成目标接口，让客户按目标接口的格式访问被适配者</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Adapter</span> :</span> <span class="keyword">public</span> Adaptee, <span class="keyword">public</span> AbstractTarget &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Request</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        SpecificRequest();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">&#125; <span class="comment">// namespace adapter </span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">Test_07_adapter_impl_1</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">"-------------------- %s --------------------\n"</span>, __FUNCTION__);</span><br><span class="line">    adapter::AbstractTarget* ptr = <span class="keyword">new</span> adapter::Adapter();</span><br><span class="line">    ptr-&gt;Request();</span><br><span class="line">    <span class="keyword">delete</span> ptr;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// -------------------- Test_07_adapter_impl_1 --------------------</span></span><br><span class="line"><span class="comment">// this is Adaptee::SpecificRequest!</span></span><br></pre></td></tr></table></figure>
</li>
</ul>
<h3 id="结构型-桥接"><a class="markdownIt-Anchor" href="#结构型-桥接"></a> 结构型 - 桥接</h3>
<ul>
<li>
<p>含义</p>
<p><code>Bridge</code> <strong>将抽象与实现分离，使它们可以独立变化</strong>。它是用组合关系代替继承关系来实现，从而降低了抽象和实现这两个可变维度的耦合度。</p>
<ul>
<li>优点
<ul>
<li>由于抽象与实现分离，所以<strong>扩展能力强</strong>；</li>
<li>其<strong>实现细节对客户透明</strong>。</li>
</ul>
</li>
<li>缺点
<ul>
<li>要求开发者针对抽象化进行设计与编程</li>
</ul>
</li>
</ul>
</li>
<li>
<p>应用场景</p>
<ul>
<li>在现实生活中，<strong>某些类具有两个或多个维度的变化</strong>，如图形既可按形状分，又可按颜色分。如何设计类似于 Photoshop 这样的软件，能画不同形状和不同颜色的图形呢？如果用继承方式，m 种形状和 n 种颜色的图形就有 m×n 种，不但对应的子类很多，而且扩展困难。</li>
<li>这样的例子还有很多，如不同颜色和字体的文字、不同品牌和功率的汽车、不同性别和职业的男女、支持不同平台和不同文件格式的媒体播放器等。</li>
</ul>
</li>
<li>
<p>示例</p>
<ul>
<li>
<p><strong>简单的抽象&amp;实现分离</strong></p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br></pre></td><td class="code"><pre><span class="line">  <span class="meta">#<span class="meta-keyword">pragma</span> once</span></span><br><span class="line">  </span><br><span class="line">  <span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdio.h&gt;</span></span></span><br><span class="line">  </span><br><span class="line">  <span class="keyword">namespace</span> bridge &#123;</span><br><span class="line">      </span><br><span class="line">  <span class="comment">/// @brief 抽象类接口</span></span><br><span class="line">  <span class="class"><span class="keyword">class</span> <span class="title">AbstractInterface</span> &#123;</span></span><br><span class="line">  <span class="keyword">public</span>:</span><br><span class="line">      AbstractInterface();</span><br><span class="line">      ~AbstractInterface();</span><br><span class="line">  </span><br><span class="line">      <span class="function"><span class="keyword">void</span> <span class="title">Request</span><span class="params">()</span></span>;</span><br><span class="line">  </span><br><span class="line">  <span class="keyword">private</span>:</span><br><span class="line">      <span class="class"><span class="keyword">class</span> <span class="title">Impl</span>;</span></span><br><span class="line">      Impl* impl_;</span><br><span class="line">  &#125;;</span><br><span class="line">  </span><br><span class="line">  <span class="comment">/// @brief 实现类接口</span></span><br><span class="line">  <span class="class"><span class="keyword">class</span> <span class="title">AbstractInterface</span>:</span>:Impl &#123;</span><br><span class="line">  <span class="keyword">public</span>:</span><br><span class="line">      <span class="function"><span class="keyword">void</span> <span class="title">Request</span><span class="params">()</span> </span>&#123;</span><br><span class="line">          <span class="built_in">printf</span>(<span class="string">"this is AbstractInterface::Impl::Request!\n"</span>);</span><br><span class="line">      &#125;</span><br><span class="line">  &#125;;</span><br><span class="line">  </span><br><span class="line">  <span class="comment">/// 抽象类接口的实现 - 调用实现类接口</span></span><br><span class="line">  AbstractInterface::AbstractInterface() &#123;</span><br><span class="line">      impl_ = <span class="keyword">new</span> Impl();</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  AbstractInterface::~AbstractInterface() &#123;</span><br><span class="line">      <span class="keyword">delete</span> impl_;</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="keyword">void</span> AbstractInterface::Request() &#123;</span><br><span class="line">      impl_-&gt;Request();</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  &#125; <span class="comment">// namespace bridge</span></span><br><span class="line">  </span><br><span class="line">  <span class="function"><span class="keyword">void</span> <span class="title">Test_08_bridge_impl_1</span><span class="params">()</span> </span>&#123;</span><br><span class="line">      <span class="built_in">printf</span>(<span class="string">"-------------------- %s --------------------\n"</span>, __FUNCTION__);</span><br><span class="line">      bridge::AbstractInterface* ptr = <span class="keyword">new</span> bridge::AbstractInterface();</span><br><span class="line">    ptr-&gt;Request();</span><br><span class="line">      <span class="keyword">delete</span> ptr;</span><br><span class="line">&#125;</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// -------------------- Test_08_bridge_impl_1 --------------------</span></span><br><span class="line">  <span class="comment">// this is AbstractInterface::Impl::Request!</span></span><br></pre></td></tr></table></figure>
</li>
<li>
<p><strong>复制的抽象&amp;实现分离</strong></p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">pragma</span> once</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdio.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> bridge &#123;</span><br><span class="line">    </span><br><span class="line"><span class="comment">/// @brief 实现化角色, 定义实现化角色的接口</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">AbstractImplementor</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="keyword">virtual</span> ~AbstractImplementor() &#123;&#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Request</span><span class="params">()</span> </span>= <span class="number">0</span>;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">/// @brief 具体实现化角色, 给出实现化角色接口的具体实现</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">ConcreteImplementorA</span> :</span> <span class="keyword">public</span> AbstractImplementor &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Request</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">"this ConcreteImplementorA::Request!\n"</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">ConcreteImplementorB</span> :</span> <span class="keyword">public</span> AbstractImplementor &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Request</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">"this ConcreteImplementorB::Request!\n"</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">/// @brief 抽象类角色, 对实现化对象的引用</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">AbstractRole</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    AbstractRole(AbstractImplementor* impl) : impl_(impl) &#123;&#125;</span><br><span class="line">    <span class="keyword">virtual</span> ~AbstractRole() &#123;&#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Request</span><span class="params">()</span> </span>= <span class="number">0</span>;</span><br><span class="line">    </span><br><span class="line"><span class="keyword">protected</span>:</span><br><span class="line">    AbstractImplementor* impl_;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">/// @brief 扩展抽象化角色, 实现父类中的业务方法</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">ExtendRole</span> :</span> <span class="keyword">public</span> AbstractRole &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    ExtendRole(AbstractImplementor* impl) : AbstractRole(impl) &#123;&#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Request</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        impl_-&gt;Request();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">&#125; <span class="comment">// namespace bridge</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">Test_08_bridge_impl_2</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">"-------------------- %s --------------------\n"</span>, __FUNCTION__);</span><br><span class="line">    bridge::AbstractImplementor* ptr_impl = <span class="keyword">new</span> bridge::ConcreteImplementorA();</span><br><span class="line">    bridge::AbstractRole* ptr_role = <span class="keyword">new</span> bridge::ExtendRole(ptr_impl);</span><br><span class="line">    ptr_role-&gt;Request();</span><br><span class="line">    <span class="keyword">delete</span> ptr_role;</span><br><span class="line">    <span class="keyword">delete</span> ptr_impl;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// -------------------- Test_08_bridge_impl_2 --------------------</span></span><br><span class="line"><span class="comment">// this ConcreteImplementorA::Request!</span></span><br></pre></td></tr></table></figure>
</li>
</ul>
</li>
</ul>
<h3 id="结构型-装饰"><a class="markdownIt-Anchor" href="#结构型-装饰"></a> 结构型 - 装饰</h3>
<ul>
<li>
<p>含义</p>
<p><code>Decorator</code> <strong>动态的给对象增加一些职责</strong>，即增加其额外的功能。</p>
<p>通常情况下，扩展一个类的功能会使用<strong>继承</strong>方式来实现。但<strong>继承具有静态特征，耦合度高，并且随着扩展功能的增多，子类会很膨胀</strong>。如果使用组合关系来创建一个包装对象（即装饰对象）来包裹真实对象，并在保持真实对象的类结构不变的前提下，为其提供额外的功能，这就是装饰模式的目标。</p>
<ul>
<li>优点
<ul>
<li>采用装饰模式扩展对象的功能<strong>比采用继承方式更加灵活</strong>。</li>
<li>可以设计出多个不同的具体装饰类，<strong>创造出多个不同行为的组合</strong>。</li>
</ul>
</li>
<li>缺点
<ul>
<li>增加了许多子类，如果过度使用会使程序变得很复杂。</li>
</ul>
</li>
</ul>
</li>
<li>
<p>应用场景</p>
<ul>
<li>在现实生活中，常常需要<strong>对现有产品增加新的功能或美化其外观</strong>，如房子装修、相片加相框等。</li>
<li>在软件开发过程中，有时想用一些现存的组件。这些组件可能只是完成了一些核心功能。但<strong>在不改变其结构的情况下，可以动态地扩展其功能</strong>。所有这些都可以釆用装饰模式来实现。</li>
</ul>
</li>
<li>
<p>示例</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">pragma</span> once</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdio.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> decorator &#123;</span><br><span class="line">    </span><br><span class="line"><span class="comment">/// @brief 抽象组件 - 被装饰的接口基类</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">AbstractComponent</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="keyword">virtual</span> ~AbstractComponent() &#123;&#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Request</span><span class="params">()</span> </span>= <span class="number">0</span>;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">/// @brief 具体组件 - 被装饰的接口派生类</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">ConcreteComponent</span> :</span> <span class="keyword">public</span> AbstractComponent &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Request</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">"this is ConcreteComponent::Request!\n"</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">/// @brief 抽象装饰</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">AbstractDecorator</span> :</span> <span class="keyword">public</span> AbstractComponent &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    AbstractDecorator(AbstractComponent* comp) : comp_(comp) &#123;&#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Request</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (comp_) comp_-&gt;Request();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line">    AbstractComponent* comp_;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">/// @brief 具体装饰</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">ConcreteDecoratorA</span> :</span> <span class="keyword">public</span> AbstractDecorator &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    ConcreteDecoratorA(AbstractComponent* comp) : AbstractDecorator(comp) &#123;&#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Request</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        PreRequest();</span><br><span class="line">        AbstractDecorator::Request();</span><br><span class="line">        PostRequest();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">protected</span>:</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">PreRequest</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">"ConcreteDecoratorA::PreRequest!\n"</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">PostRequest</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">"ConcreteDecoratorA::PostRequest!\n"</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">&#125; <span class="comment">// namespace decorator</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">Test_09_decorator_impl_1</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">"-------------------- %s --------------------\n"</span>, __FUNCTION__);</span><br><span class="line">    decorator::AbstractComponent* ptr_comp = <span class="keyword">new</span> decorator::ConcreteComponent();</span><br><span class="line">    ptr_comp-&gt;Request();    <span class="comment">// 原有组件该有的功能不变</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">// 对现有组件的功能进行扩展</span></span><br><span class="line">    decorator::AbstractDecorator* ptr_decorator = <span class="keyword">new</span> decorator::ConcreteDecoratorA(ptr_comp);</span><br><span class="line">    ptr_decorator-&gt;Request();</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">delete</span> ptr_decorator;</span><br><span class="line">    <span class="keyword">delete</span> ptr_comp;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// -------------------- Test_09_decorator_impl_1 --------------------</span></span><br><span class="line"><span class="comment">// this is ConcreteComponent::Request!</span></span><br><span class="line"><span class="comment">// ConcreteDecoratorA::PreRequest!</span></span><br><span class="line"><span class="comment">// this is ConcreteComponent::Request!</span></span><br><span class="line"><span class="comment">// ConcreteDecoratorA::PostRequest!</span></span><br></pre></td></tr></table></figure>
</li>
</ul>
<h3 id="结构型-外观"><a class="markdownIt-Anchor" href="#结构型-外观"></a> 结构型 - 外观</h3>
<ul>
<li>
<p>含义</p>
<p><code>Facade</code> 为多个复杂的子系统<strong>提供一个一致的接口</strong>，使这些子系统更加容易被访问。</p>
<ul>
<li>优点
<ul>
<li>降低了子系统与客户端之间的耦合度，使得子系统的变化不会影响调用它的客户类。</li>
<li>对客户屏蔽了子系统组件，减少了客户处理的对象数目，并使得子系统使用起来更加容易。</li>
<li>降低了大型软件系统中的编译依赖性，简化了系统在不同平台之间的移植过程，因为编译一个子系统不会影响其他的子系统，也不会影响外观对象。</li>
</ul>
</li>
<li>缺点
<ul>
<li>不能很好地限制客户使用子系统类。</li>
<li><strong>增加新的子系统可能需要修改外观类或客户端的源代码，违背了“开闭原则”</strong>。</li>
</ul>
</li>
</ul>
</li>
<li>
<p>应用场景</p>
<ul>
<li>在现实生活中，常常存在办事较复杂的例子，如办房产证或注册一家公司，有时要同多个部门联系，这时要是有一个综合部门能解决一切手续问题就好了。</li>
<li>软件设计也是这样，当一个系统的功能越来越强，子系统会越来越多，客户对系统的访问也变得越来越复杂。这时如果系统内部发生改变，客户端也要跟着改变，这<strong>违背了“开闭原则”，也违背了“迪米特法则”</strong>，</li>
</ul>
<p>所以有必要<strong>为多个子系统提供一个统一的接口，从而降低系统的耦合度</strong>，这就是外观模式的目标。</p>
</li>
<li>
<p>示例</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">pragma</span> once</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;iostream&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> facade &#123;</span><br><span class="line">    </span><br><span class="line"><span class="comment">/// @brief 具体实现子模块</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">SubModuleImplementorA</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">PreRequest</span> <span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">"SubModuleImplementorA::PreRequest!\n"</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">SubModuleImplementorB</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">RealRequest</span> <span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">"SubModuleImplementorB::RealRequest!\n"</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">SubModuleImplementorC</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">PostRequest</span> <span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">"SubModuleImplementorC::PostRequest!\n"</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">/// @brief 外观角色</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Facade</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    Facade() &#123;</span><br><span class="line">        implA_.reset(<span class="keyword">new</span> SubModuleImplementorA());</span><br><span class="line">        implB_.reset(<span class="keyword">new</span> SubModuleImplementorB());</span><br><span class="line">        implC_.reset(<span class="keyword">new</span> SubModuleImplementorC());</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">Request</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        implA_-&gt;PreRequest();</span><br><span class="line">        implB_-&gt;RealRequest();</span><br><span class="line">        implC_-&gt;PostRequest();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line">    <span class="built_in">std</span>::<span class="built_in">shared_ptr</span>&lt;SubModuleImplementorA&gt; implA_;</span><br><span class="line">    <span class="built_in">std</span>::<span class="built_in">shared_ptr</span>&lt;SubModuleImplementorB&gt; implB_;</span><br><span class="line">    <span class="built_in">std</span>::<span class="built_in">shared_ptr</span>&lt;SubModuleImplementorC&gt; implC_;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">&#125; <span class="comment">// namespace facade</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">Test_10_facade_impl_1</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">"-------------------- %s --------------------\n"</span>, __FUNCTION__);</span><br><span class="line">    <span class="built_in">std</span>::<span class="built_in">shared_ptr</span>&lt;facade::Facade&gt; ptr(<span class="keyword">new</span> facade::Facade());</span><br><span class="line">    ptr-&gt;Request();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// -------------------- Test_10_facade_impl_1 --------------------</span></span><br><span class="line"><span class="comment">// SubModuleImplementorA::PreRequest!</span></span><br><span class="line"><span class="comment">// SubModuleImplementorB::RealRequest!</span></span><br><span class="line"><span class="comment">// SubModuleImplementorC::PostRequest!</span></span><br></pre></td></tr></table></figure>
</li>
</ul>
<h3 id="结构型-享元"><a class="markdownIt-Anchor" href="#结构型-享元"></a> 结构型 - 享元</h3>
<ul>
<li>
<p>含义</p>
<p><code>Flyweight</code> 运用共享技术来有效地支持大量细粒度对象的复用。</p>
<ul>
<li>优点
<ul>
<li>相同对象只要保存一份，这降低了系统中对象的数量，从而降低了系统中细粒度对象给内存带来的压力。</li>
</ul>
</li>
<li>缺点
<ul>
<li><strong>为了使对象可以共享，需要将一些不能共享的状态外部化</strong>，这将增加程序的复杂性。</li>
<li>读取享元模式的外部状态会<strong>使得运行时间稍微变长</strong>。</li>
</ul>
</li>
</ul>
</li>
<li>
<p>应用场景</p>
<ul>
<li>在面向对象程序设计过程中，<strong>有时会面临要创建大量相同或相似对象实例的问题</strong>。创建那么多的对象将会耗费很多的系统资源，它是系统性能提高的一个瓶颈。</li>
<li>例如，围棋和五子棋中的黑白棋子，图像中的坐标点或颜色，局域网中的路由器、交换机和集线器，教室里的桌子和凳子等。</li>
<li>这些对象有很多相似的地方，<strong>如果能把它们相同的部分提取出来共享，则能节省大量的系统资源</strong>，这就是享元模式的产生背景。</li>
</ul>
</li>
<li>
<p>示例</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">pragma</span> once</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;map&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;string&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> flyweight &#123;</span><br><span class="line">    </span><br><span class="line"><span class="comment">/// @brief 非享元类, 以参数的形式注入具体享元的相关方法中</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">UnsharableConcreteFlyweight</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    UnsharableConcreteFlyweight(<span class="keyword">const</span> <span class="built_in">std</span>::<span class="built_in">string</span>&amp; content) : content_(content) &#123;&#125;</span><br><span class="line">    <span class="keyword">const</span> <span class="built_in">std</span>::<span class="function"><span class="built_in">string</span>&amp; <span class="title">GetContent</span><span class="params">()</span> <span class="keyword">const</span> </span>&#123; <span class="keyword">return</span> content_; &#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line">    <span class="built_in">std</span>::<span class="built_in">string</span> content_;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">/// @brief 抽象享元类, 为具体享元规范需要实现的公共接口</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">AbstractFlyweight</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="keyword">virtual</span> ~AbstractFlyweight() &#123;&#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Run</span><span class="params">(UnsharableConcreteFlyweight* unsharable_content_ptr)</span> </span>= <span class="number">0</span>;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">/// @brief 具体享元类, 实现抽象享元角色中所规定的接口</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">ConcreteFlyweightA</span> :</span> <span class="keyword">public</span> AbstractFlyweight &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Run</span><span class="params">(UnsharableConcreteFlyweight* unsharable_content_ptr)</span> </span>&#123;</span><br><span class="line">        <span class="built_in">std</span>::<span class="built_in">cout</span> &lt;&lt; <span class="string">"ConcreteFlyweightA::Run!"</span> &lt;&lt; <span class="built_in">std</span>::<span class="built_in">endl</span>;</span><br><span class="line">        <span class="built_in">std</span>::<span class="built_in">cout</span> &lt;&lt; unsharable_content_ptr-&gt;GetContent() &lt;&lt; <span class="built_in">std</span>::<span class="built_in">endl</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">ConcreteFlyweightB</span> :</span> <span class="keyword">public</span> AbstractFlyweight &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Run</span><span class="params">(UnsharableConcreteFlyweight* unsharable_content_ptr)</span> </span>&#123;</span><br><span class="line">        <span class="built_in">std</span>::<span class="built_in">cout</span> &lt;&lt; <span class="string">"ConcreteFlyweightB::Run!"</span> &lt;&lt; <span class="built_in">std</span>::<span class="built_in">endl</span>;</span><br><span class="line">        <span class="built_in">std</span>::<span class="built_in">cout</span> &lt;&lt; unsharable_content_ptr-&gt;GetContent() &lt;&lt; <span class="built_in">std</span>::<span class="built_in">endl</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">/// @brief 享元工厂类</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">FlyweightFactory</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="keyword">enum</span> FlyweightType &#123;</span><br><span class="line">        ConcreteA = <span class="number">0</span>,</span><br><span class="line">        ConcreteB,</span><br><span class="line">    &#125;;</span><br><span class="line"></span><br><span class="line">    ~FlyweightFactory() &#123;</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">auto</span> it = fly_weights_.begin(); it != fly_weights_.end(); it++) &#123;</span><br><span class="line">            <span class="keyword">if</span> (it-&gt;second) <span class="keyword">delete</span> it-&gt;second;</span><br><span class="line">        &#125;</span><br><span class="line">        fly_weights_.clear();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function">AbstractFlyweight* <span class="title">GetFlyweight</span><span class="params">(<span class="keyword">const</span> <span class="built_in">std</span>::<span class="built_in">string</span>&amp; key, <span class="keyword">const</span> FlyweightType&amp; type = ConcreteA)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">auto</span> it = fly_weights_.find(key);</span><br><span class="line">        <span class="keyword">if</span> (fly_weights_.end() == it) &#123;</span><br><span class="line">            AbstractFlyweight* ptr = <span class="literal">nullptr</span>;</span><br><span class="line">            <span class="keyword">if</span> (ConcreteA == type) &#123;</span><br><span class="line">                ptr = <span class="keyword">new</span> ConcreteFlyweightA();</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">else</span> <span class="keyword">if</span> (ConcreteB == type) &#123;</span><br><span class="line">                ptr = <span class="keyword">new</span> ConcreteFlyweightB();</span><br><span class="line">            &#125;</span><br><span class="line">            fly_weights_[key] = ptr;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> fly_weights_[key];</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line">    <span class="built_in">std</span>::<span class="built_in">map</span>&lt;<span class="built_in">std</span>::<span class="built_in">string</span>, AbstractFlyweight*&gt; fly_weights_;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">&#125; <span class="comment">// namespace flyweight</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">Test_11_flyweight_impl_1</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">"-------------------- %s --------------------\n"</span>, __FUNCTION__);</span><br><span class="line">    <span class="built_in">std</span>::<span class="built_in">shared_ptr</span>&lt;flyweight::UnsharableConcreteFlyweight&gt; unsharable_content_ptr_1(<span class="keyword">new</span> flyweight::UnsharableConcreteFlyweight(<span class="string">"unsharable_content_ptr_1"</span>));</span><br><span class="line">    <span class="built_in">std</span>::<span class="built_in">shared_ptr</span>&lt;flyweight::UnsharableConcreteFlyweight&gt; unsharable_content_ptr_2(<span class="keyword">new</span> flyweight::UnsharableConcreteFlyweight(<span class="string">"unsharable_content_ptr_2"</span>));</span><br><span class="line"></span><br><span class="line">    <span class="built_in">std</span>::<span class="built_in">shared_ptr</span>&lt;flyweight::FlyweightFactory&gt; ptr(<span class="keyword">new</span> flyweight::FlyweightFactory());</span><br><span class="line">    flyweight::AbstractFlyweight* flyweight_ptr_A_red = ptr-&gt;GetFlyweight(<span class="string">"Red"</span>);</span><br><span class="line">    flyweight::AbstractFlyweight* flyweight_ptr_A_point = ptr-&gt;GetFlyweight(<span class="string">"Point"</span>);</span><br><span class="line">    </span><br><span class="line">    flyweight_ptr_A_red-&gt;Run(unsharable_content_ptr_1.get());</span><br><span class="line">    flyweight_ptr_A_point-&gt;Run(unsharable_content_ptr_2.get());</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// -------------------- Test_11_flyweight_impl_1 --------------------</span></span><br><span class="line"><span class="comment">// ConcreteFlyweightA::Run!</span></span><br><span class="line"><span class="comment">// unsharable_content_ptr_1</span></span><br><span class="line"><span class="comment">// ConcreteFlyweightA::Run!</span></span><br><span class="line"><span class="comment">// unsharable_content_ptr_2</span></span><br></pre></td></tr></table></figure>
</li>
</ul>
<h3 id="结构型-组合"><a class="markdownIt-Anchor" href="#结构型-组合"></a> 结构型 - 组合</h3>
<ul>
<li>
<p>含义</p>
<p><code>Composite</code> 将对象<strong>组合成树状层次结构</strong>，使用户<strong>对单个对象和组合对象具有一致的访问性</strong>。</p>
<ul>
<li>优点
<ul>
<li><strong>使得客户端代码可以一致地处理单个对象和组合对象</strong>，无须关心自己处理的是单个对象，还是组合对象，这简化了客户端代码；</li>
<li>更容易在组合体内加入新的对象，客户端不会因为加入了新的对象而更改源代码，<strong>满足“开闭原则”</strong>；</li>
</ul>
</li>
<li>缺点
<ul>
<li>设计较复杂，客户端需要花更多时间理清类之间的层次关系；</li>
<li>不容易限制容器中的构件；</li>
<li>不容易用继承的方法来增加构件的新功能；</li>
</ul>
</li>
</ul>
</li>
<li>
<p>应用场景</p>
<ul>
<li>在现实生活中，存在很多“部分-整体”的关系，例如，大学中的部门与学院、总公司中的部门与分公司、学习用品中的书与书包、生活用品中的衣月艮与衣柜以及厨房中的锅碗瓢盆等。</li>
<li>在软件开发中也是这样，例如，文件系统中的文件与文件夹、窗体程序中的简单控件与容器控件等。对这些简单对象与复合对象的处理，如果用组合模式来实现会很方便。</li>
</ul>
</li>
<li>
<p>示例</p>
<p><strong>组合模式分为<code>透明式</code>的组合模式和<code>安全式</code>的组合模式</strong>。</p>
<ul>
<li>
<p><strong>透明方式</strong></p>
<ul>
<li>由于<strong>抽象构件声明了所有子类中的全部方法</strong>，所以客户端无须区别树叶对象和树枝对象，对客户端来说是透明的。</li>
<li>但其缺点是：树叶构件本来没有 Add()、Remove() 及 GetChild() 方法，却要实现它们（空实现或抛异常），这样会带来一些安全性问题。</li>
</ul>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br></pre></td><td class="code"><pre><span class="line">  <span class="meta">#<span class="meta-keyword">pragma</span> once</span></span><br><span class="line">  </span><br><span class="line">  <span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;iostream&gt;</span></span></span><br><span class="line">  <span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;string&gt;</span></span></span><br><span class="line">  <span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;vector&gt;</span></span></span><br><span class="line">  </span><br><span class="line">  <span class="keyword">namespace</span> composite &#123;</span><br><span class="line">      </span><br><span class="line">  <span class="comment">/// @brief 抽象构件, 为树叶构件和树枝构件声明公共接口，并实现它们的默认行为</span></span><br><span class="line">  <span class="comment">///        - 透明式: 声明访问和管理子类的接口</span></span><br><span class="line">  <span class="comment">///        - 安全式: 不声明访问和管理子类的接口，管理工作由树枝构件完成</span></span><br><span class="line">  <span class="class"><span class="keyword">class</span> <span class="title">AbstractTransparentComponent</span> &#123;</span></span><br><span class="line">  <span class="keyword">public</span>:</span><br><span class="line">      <span class="keyword">virtual</span> ~AbstractTransparentComponent() &#123;&#125;</span><br><span class="line">  </span><br><span class="line">      <span class="comment">// 透明式下, 需声明所有子类中的全部方法</span></span><br><span class="line">      <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Add</span><span class="params">(AbstractTransparentComponent* comp)</span> </span>= <span class="number">0</span>;</span><br><span class="line">      <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Remove</span><span class="params">(AbstractTransparentComponent* comp)</span> </span>= <span class="number">0</span>;</span><br><span class="line">      <span class="function"><span class="keyword">virtual</span> AbstractTransparentComponent* <span class="title">GetChild</span><span class="params">(<span class="keyword">const</span> <span class="keyword">int</span> id)</span> </span>= <span class="number">0</span>;</span><br><span class="line">  </span><br><span class="line">      <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Operation</span><span class="params">()</span> </span>= <span class="number">0</span>;</span><br><span class="line">  &#125;;</span><br><span class="line">  </span><br><span class="line">  <span class="comment">/// @brief 树叶构件, 组合中的叶节点对象，它没有子节点，用于实现抽象构件角色中声明的公共接口</span></span><br><span class="line">  <span class="class"><span class="keyword">class</span> <span class="title">LeafTransparentComponent</span> :</span> <span class="keyword">public</span> AbstractTransparentComponent &#123;</span><br><span class="line">  <span class="keyword">public</span>:</span><br><span class="line">      LeafTransparentComponent(<span class="keyword">const</span> <span class="built_in">std</span>::<span class="built_in">string</span>&amp; name) : name_(name) &#123;&#125;</span><br><span class="line">  </span><br><span class="line">      <span class="comment">// 透明式下, 树叶构件需要实现的不必要接口 (可空实现或跑出异常)</span></span><br><span class="line">      <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Add</span><span class="params">(AbstractTransparentComponent* comp)</span> </span>&#123;</span><br><span class="line">          <span class="built_in">printf</span>(<span class="string">"Error! Leaf can't realize Add!\n"</span>);</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Remove</span><span class="params">(AbstractTransparentComponent* comp)</span> </span>&#123;</span><br><span class="line">          <span class="built_in">printf</span>(<span class="string">"Error! Leaf can't realize Remove!\n"</span>);</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="function"><span class="keyword">virtual</span> AbstractTransparentComponent* <span class="title">GetChild</span><span class="params">(<span class="keyword">const</span> <span class="keyword">int</span> id)</span> </span>&#123;</span><br><span class="line">          <span class="built_in">printf</span>(<span class="string">"Error! Leaf can't realize GetChild!\n"</span>);</span><br><span class="line">          <span class="keyword">return</span> <span class="literal">nullptr</span>;</span><br><span class="line">      &#125;</span><br><span class="line">  </span><br><span class="line">      <span class="comment">// 树叶构件切实需要实现的接口</span></span><br><span class="line">      <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Operation</span><span class="params">()</span> </span>&#123;</span><br><span class="line">          <span class="built_in">printf</span>(<span class="string">"this(%s) is LeafTransparentComponent::Operation!\n"</span>, name_.c_str());</span><br><span class="line">      &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="keyword">private</span>:</span><br><span class="line">      <span class="built_in">std</span>::<span class="built_in">string</span> name_;</span><br><span class="line">  &#125;;</span><br><span class="line">  </span><br><span class="line">  <span class="comment">/// @brief 树枝构件, 组合中的分支节点对象，它有子节点。它实现了抽象构件角色中声明的接口，主要作用是存储和管理子部件</span></span><br><span class="line">  <span class="class"><span class="keyword">class</span> <span class="title">CompositeTransparentComponent</span> :</span> <span class="keyword">public</span> AbstractTransparentComponent &#123;</span><br><span class="line">  <span class="keyword">public</span>:</span><br><span class="line">      <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Add</span><span class="params">(AbstractTransparentComponent* comp)</span> </span>&#123;</span><br><span class="line">          children_.emplace_back(comp);</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Remove</span><span class="params">(AbstractTransparentComponent* comp)</span> </span>&#123;</span><br><span class="line">          <span class="keyword">for</span> (<span class="keyword">auto</span> it = children_.begin(); it != children_.end(); it++) &#123;</span><br><span class="line">              <span class="keyword">if</span> (comp == (*it)) &#123;</span><br><span class="line">                  children_.erase(it++);</span><br><span class="line">                  <span class="keyword">break</span>;</span><br><span class="line">              &#125;</span><br><span class="line">          &#125;</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="function"><span class="keyword">virtual</span> AbstractTransparentComponent* <span class="title">GetChild</span><span class="params">(<span class="keyword">const</span> <span class="keyword">int</span> id)</span> </span>&#123;</span><br><span class="line">          <span class="keyword">if</span> (id &gt;= <span class="number">0</span> &amp;&amp; id &lt; children_.size()) <span class="keyword">return</span> children_[id];</span><br><span class="line">          <span class="keyword">return</span> <span class="literal">nullptr</span>;</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Operation</span><span class="params">()</span> </span>&#123;</span><br><span class="line">          <span class="keyword">for</span> (<span class="keyword">auto</span>* child : children_) &#123;</span><br><span class="line">              child-&gt;Operation();</span><br><span class="line">          &#125;</span><br><span class="line">      &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="keyword">private</span>:</span><br><span class="line">      <span class="built_in">std</span>::<span class="built_in">vector</span>&lt;AbstractTransparentComponent*&gt; children_;</span><br><span class="line">  &#125;;</span><br><span class="line">  </span><br><span class="line">  &#125; <span class="comment">// namespace composite</span></span><br><span class="line">  </span><br><span class="line">  <span class="function"><span class="keyword">void</span> <span class="title">Test_12_composite_impl_1</span><span class="params">()</span> </span>&#123;</span><br><span class="line">      <span class="built_in">printf</span>(<span class="string">"-------------------- %s --------------------\n"</span>, __FUNCTION__);</span><br><span class="line">      <span class="built_in">std</span>::<span class="built_in">shared_ptr</span>&lt;composite::AbstractTransparentComponent&gt; composite_ptr(<span class="keyword">new</span> composite::CompositeTransparentComponent());</span><br><span class="line">  </span><br><span class="line">      <span class="built_in">std</span>::<span class="built_in">shared_ptr</span>&lt;composite::AbstractTransparentComponent&gt; leaf_ptr_A(<span class="keyword">new</span> composite::LeafTransparentComponent(<span class="string">"leaf A"</span>));</span><br><span class="line">      <span class="built_in">std</span>::<span class="built_in">shared_ptr</span>&lt;composite::AbstractTransparentComponent&gt; leaf_ptr_B(<span class="keyword">new</span> composite::LeafTransparentComponent(<span class="string">"leaf B"</span>));</span><br><span class="line">      <span class="built_in">std</span>::<span class="built_in">shared_ptr</span>&lt;composite::AbstractTransparentComponent&gt; leaf_ptr_C(<span class="keyword">new</span> composite::LeafTransparentComponent(<span class="string">"leaf C"</span>));</span><br><span class="line">  </span><br><span class="line">      composite_ptr-&gt;Add(leaf_ptr_A.get());</span><br><span class="line">      composite_ptr-&gt;Add(leaf_ptr_B.get());</span><br><span class="line">      composite_ptr-&gt;Add(leaf_ptr_C.get());</span><br><span class="line">  </span><br><span class="line">      composite::AbstractTransparentComponent* tmp_ptr = composite_ptr-&gt;GetChild(<span class="number">1</span>);</span><br><span class="line">      tmp_ptr-&gt;Operation();</span><br><span class="line">      composite_ptr-&gt;Remove(leaf_ptr_B.get());</span><br><span class="line"></span><br><span class="line">      composite_ptr-&gt;Operation();</span><br><span class="line">&#125;</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// -------------------- Test_12_composite_impl_1 --------------------</span></span><br><span class="line"><span class="comment">// this(leaf B) is LeafTransparentComponent::Operation!</span></span><br><span class="line">  <span class="comment">// this(leaf A) is LeafTransparentComponent::Operation!</span></span><br><span class="line">  <span class="comment">// this(leaf C) is LeafTransparentComponent::Operation!</span></span><br></pre></td></tr></table></figure>
</li>
<li>
<p><strong>安全方式</strong></p>
<ul>
<li>将管理子构件的方法移到树枝构件中，抽象构件和树叶构件没有对子对象的管理方法，这样就避免了上一种方式的安全性问题，</li>
<li>但由于叶子和分支有不同的接口，<strong>客户端在调用时要知道树叶对象和树枝对象的存在</strong>，所以失去了透明性。</li>
</ul>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">pragma</span> once</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;string&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;vector&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> composite &#123;</span><br><span class="line"></span><br><span class="line"><span class="comment">/// @brief 抽象构件, 为树叶构件和树枝构件声明公共接口，并实现它们的默认行为</span></span><br><span class="line"><span class="comment">///        - 透明式: 声明访问和管理子类的接口</span></span><br><span class="line"><span class="comment">///        - 安全式: 不声明访问和管理子类的接口，管理工作由树枝构件完成</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">AbstractSafeComponent</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="keyword">virtual</span> ~AbstractSafeComponent() &#123;&#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Operation</span><span class="params">()</span> </span>= <span class="number">0</span>;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">/// @brief 树叶构件, 组合中的叶节点对象，它没有子节点，用于实现抽象构件角色中声明的公共接口</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">LeafSafeComponent</span> :</span> <span class="keyword">public</span> AbstractSafeComponent &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    LeafSafeComponent(<span class="keyword">const</span> <span class="built_in">std</span>::<span class="built_in">string</span>&amp; name) : name_(name) &#123;&#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 树叶构件切实需要实现的接口</span></span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Operation</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">"this(%s) is LeafSafeComponent::Operation!\n"</span>, name_.c_str());</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line">    <span class="built_in">std</span>::<span class="built_in">string</span> name_;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">/// @brief 树枝构件, 组合中的分支节点对象，它有子节点。它实现了抽象构件角色中声明的接口，主要作用是存储和管理子部件</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">CompositeSafeComponent</span> :</span> <span class="keyword">public</span> AbstractSafeComponent &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="comment">// 安全式下, 由树枝构件自己实现对树叶构件的管理</span></span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Add</span><span class="params">(AbstractSafeComponent* comp)</span> </span>&#123;</span><br><span class="line">        children_.emplace_back(comp);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Remove</span><span class="params">(AbstractSafeComponent* comp)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">auto</span> it = children_.begin(); it != children_.end(); it++) &#123;</span><br><span class="line">            <span class="keyword">if</span> (comp == (*it)) &#123;</span><br><span class="line">                children_.erase(it++);</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> AbstractSafeComponent* <span class="title">GetChild</span><span class="params">(<span class="keyword">const</span> <span class="keyword">int</span> id)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (id &gt;= <span class="number">0</span> &amp;&amp; id &lt; children_.size()) <span class="keyword">return</span> children_[id];</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">nullptr</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Operation</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">auto</span>* child : children_) &#123;</span><br><span class="line">            child-&gt;Operation();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line">    <span class="built_in">std</span>::<span class="built_in">vector</span>&lt;AbstractSafeComponent*&gt; children_;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">&#125; <span class="comment">// namespace composite</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">Test_12_composite_impl_2</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">"-------------------- %s --------------------\n"</span>, __FUNCTION__);</span><br><span class="line">    composite::AbstractSafeComponent* composite_ptr = <span class="keyword">new</span> composite::CompositeSafeComponent();</span><br><span class="line">    </span><br><span class="line">    composite::AbstractSafeComponent* leaf_ptr_A = <span class="keyword">new</span> composite::LeafSafeComponent(<span class="string">"leaf A"</span>);</span><br><span class="line">    composite::AbstractSafeComponent* leaf_ptr_B = <span class="keyword">new</span> composite::LeafSafeComponent(<span class="string">"leaf B"</span>);</span><br><span class="line">    composite::AbstractSafeComponent* leaf_ptr_C = <span class="keyword">new</span> composite::LeafSafeComponent(<span class="string">"leaf C"</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 对树叶构件的操作</span></span><br><span class="line">    &#123;</span><br><span class="line">        composite::CompositeSafeComponent* composite_son_ptr = <span class="keyword">dynamic_cast</span>&lt;composite::CompositeSafeComponent*&gt;(composite_ptr);</span><br><span class="line"></span><br><span class="line">        composite_son_ptr-&gt;Add(leaf_ptr_A);</span><br><span class="line">        composite_son_ptr-&gt;Add(leaf_ptr_B);</span><br><span class="line">        composite_son_ptr-&gt;Add(leaf_ptr_C);</span><br><span class="line"></span><br><span class="line">        composite::AbstractSafeComponent* tmp_ptr = composite_son_ptr-&gt;GetChild(<span class="number">1</span>);</span><br><span class="line">        tmp_ptr-&gt;Operation();</span><br><span class="line">        composite_son_ptr-&gt;Remove(leaf_ptr_B);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    composite_ptr-&gt;Operation();</span><br><span class="line"></span><br><span class="line">    <span class="keyword">delete</span> composite_ptr;</span><br><span class="line">    <span class="keyword">delete</span> leaf_ptr_A;</span><br><span class="line">    <span class="keyword">delete</span> leaf_ptr_B;</span><br><span class="line">    <span class="keyword">delete</span> leaf_ptr_C;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// -------------------- Test_12_composite_impl_2 --------------------</span></span><br><span class="line"><span class="comment">// this(leaf B) is LeafSafeComponent::Operation!</span></span><br><span class="line"><span class="comment">// this(leaf A) is LeafSafeComponent::Operation!</span></span><br><span class="line"><span class="comment">// this(leaf C) is LeafSafeComponent::Operation!</span></span><br></pre></td></tr></table></figure>
</li>
</ul>
</li>
</ul>
<h3 id="行为型-模板方法"><a class="markdownIt-Anchor" href="#行为型-模板方法"></a> 行为型 - 模板方法</h3>
<ul>
<li>
<p>含义</p>
<p><code>TemplateMethod</code> <strong>定义一个操作中的算法骨架，而将算法的一些步骤延迟到子类中</strong>，使得<strong>子类可以不改变该算法结构的情况下重定义该算法的某些特定步骤</strong>。</p>
<ul>
<li>优点
<ul>
<li>它<strong>封装了不变部分，扩展可变部分</strong>。它把认为是不变部分的算法封装到父类中实现，而把可变部分算法由子类继承实现，便于子类继续扩展。</li>
<li>它在父类中提取了公共的部分代码，便于代码复用。</li>
<li>部分方法是由子类实现的，因此子类可以通过扩展方式增加相应的功能，<strong>符合开闭原则</strong>。</li>
</ul>
</li>
<li>缺点
<ul>
<li>对每个不同的实现都需要定义一个子类，这会导致<strong>类的个数增加</strong>，系统更加庞大，设计也更加抽象。</li>
<li>父类中的抽象方法由子类实现，<strong>子类执行的结果会影响父类的结果</strong>，这导致一种反向的控制结构，它提高了代码阅读的难度。</li>
</ul>
</li>
</ul>
</li>
<li>
<p>应用场景</p>
<ul>
<li>在面向对象程序设计过程中，程序员常常会遇到这种情况：设计一个系统时知道了算法所需的关键步骤，而且确定了这些步骤的执行顺序，但某些步骤的具体实现还未知，或者说某些步骤的实现与具体的环境相关。</li>
<li>生活中的例子: <strong>一个人每天会起床、吃饭、做事、睡觉等，其中“做事”的内容每天可能不同</strong>。</li>
<li>我们把这些规定了流程或格式的实例定义成模板，允许使用者根据自己的需求去更新它，例如，简历模板、论文模板、Word 中模板文件等。</li>
</ul>
</li>
<li>
<p>实现方式</p>
<p>抽象类负责给出一个算法的轮廓和骨架, 即定义两种类型的方法</p>
<ul>
<li><strong>模板方法</strong>:  定义了算法的骨架，按某种顺序调用其包含的基本方法</li>
<li><strong>基本方法</strong>:
<ul>
<li><strong>抽象方法</strong>：在抽象类中申明，由具体子类实现</li>
<li><strong>具体方法</strong>：在抽象类中已经实现，在具体子类中可以继承或重写它</li>
<li><strong>钩子方法</strong>：在抽象类中已经实现，包括用于判断的逻辑方法和需要子类重写的空方法两种</li>
</ul>
</li>
</ul>
</li>
<li>
<p>示例</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">pragma</span> once</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;iostream&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> template_method &#123;</span><br><span class="line">    </span><br><span class="line"><span class="comment">/// @brief 抽象类, 给出一个算法的轮廓和骨架</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">AbstractClass</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="keyword">virtual</span> ~AbstractClass() &#123;&#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/// @brief 模板方法, 定义了算法的骨架，按某种顺序调用其包含的基本方法</span></span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">TemplateMethod</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        SpecificMethodA();</span><br><span class="line">        <span class="keyword">if</span> (HookMethodB()) &#123;</span><br><span class="line">            HookMethodA();</span><br><span class="line">        &#125;</span><br><span class="line">        AbstractMethod();</span><br><span class="line">        SpecificMethodB();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">protected</span>:</span><br><span class="line">    <span class="comment">/// @brief 基本方法, 可以有三种</span></span><br><span class="line">    <span class="comment">///             - 抽象方法：在抽象类中申明，由具体子类实现</span></span><br><span class="line">    <span class="comment">///             - 具体方法：在抽象类中已经实现，在具体子类中可以继承或重写它</span></span><br><span class="line">    <span class="comment">///             - 钩子方法：在抽象类中已经实现，包括用于判断的逻辑方法和需要子类重写的空方法两种</span></span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">AbstractMethod</span><span class="params">()</span> </span>= <span class="number">0</span>;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">SpecificMethodA</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">"this is AbstractClass::SpecificMethodA!\n"</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">SpecificMethodB</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">"this is AbstractClass::SpecificMethodB!\n"</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">HookMethodA</span><span class="params">()</span> </span>&#123;    <span class="comment">// 通常为空实现</span></span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">"this is AbstractClass::HookMethodA!\n"</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">bool</span> <span class="title">HookMethodB</span><span class="params">()</span> </span>&#123; <span class="keyword">return</span> <span class="literal">false</span>; &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">/// @brief 具体类, 实现抽象类中所定义的抽象方法和钩子方法</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">ConcreteClass</span> :</span> <span class="keyword">public</span> AbstractClass &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">AbstractMethod</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">"this is ConcreteClass::AbstractMethod!\n"</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">protected</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">SpecificMethodB</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">"this is ConcreteClass::SpecificMethodB!\n"</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">HookMethodA</span><span class="params">()</span> </span>&#123;    <span class="comment">// 通常为空实现</span></span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">"this is ConcreteClass::HookMethodA!\n"</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">bool</span> <span class="title">HookMethodB</span><span class="params">()</span> </span>&#123; <span class="keyword">return</span> <span class="literal">true</span>; &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">&#125; <span class="comment">// namespace template_method</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">Test_13_composite_impl_1</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">"-------------------- %s --------------------\n"</span>, __FUNCTION__);</span><br><span class="line">    template_method::AbstractClass* ptr = <span class="keyword">new</span> template_method::ConcreteClass();</span><br><span class="line">    ptr-&gt;TemplateMethod();</span><br><span class="line"></span><br><span class="line">    <span class="keyword">delete</span> ptr;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// -------------------- Test_13_template_method_impl_1 --------------------</span></span><br><span class="line"><span class="comment">// this is AbstractClass::SpecificMethodA!</span></span><br><span class="line"><span class="comment">// this is ConcreteClass::HookMethodA!</span></span><br><span class="line"><span class="comment">// this is ConcreteClass::AbstractMethod!</span></span><br><span class="line"><span class="comment">// this is ConcreteClass::SpecificMethodB!</span></span><br></pre></td></tr></table></figure>
</li>
</ul>
<h3 id="行为型-策略"><a class="markdownIt-Anchor" href="#行为型-策略"></a> 行为型 - 策略</h3>
<ul>
<li>
<p>含义</p>
<p><code>Strategy</code> 定义了一系列算法，并<strong>将每个算法封装起来，使它们可以相互替换，且算法的改变不会影响使用算法的客户</strong>。</p>
<ul>
<li>优点
<ul>
<li>多重条件语句不易维护，而使用策略模式可以<strong>避免使用多重条件语句</strong>。</li>
<li>策略模式提供了一系列的可供重用的算法族，恰当使用继承可以把算法族的公共代码转移到父类里面，从而<strong>避免重复的代码</strong>。</li>
<li>策略模式<strong>可以提供相同行为的不同实现</strong>，客户可以根据不同时间或空间要求选择不同的。</li>
<li>策略模式提供了<strong>对开闭原则的完美支持</strong>，可以在不修改原代码的情况下，灵活增加新算法。</li>
<li>策略模式把算法的使用放到环境类中，而算法的实现移到具体策略类中，实现了二者的分离。</li>
</ul>
</li>
<li>缺点
<ul>
<li><strong>客户端必须理解所有策略算法的区别，以便适时选择恰当的算法类</strong>。</li>
<li>策略模式造成很多的策略类。</li>
</ul>
</li>
</ul>
</li>
<li>
<p>应用场景</p>
<ul>
<li>在现实生活中常常遇到<strong>实现某种目标存在多种策略可供选择的情况</strong>，例如，出行旅游可以乘坐飞机、乘坐火车、骑自行车或自己开私家车等，超市促销可以釆用打折、送商品、送积分等方法。</li>
<li>在软件开发中也常常遇到类似的情况，当<strong>实现某一个功能存在多种算法或者策略，我们可以根据环境或者条件的不同选择不同的算法或者策略来完成该功能</strong>，如数据排序策略有冒泡排序、选择排序、插入排序、二叉树排序等。</li>
</ul>
</li>
<li>
<p>示例</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">pragma</span> once</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdio.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> strategy &#123;</span><br><span class="line">    </span><br><span class="line"><span class="comment">/// @brief 抽象策略类, 定义了一个公共接口，各种不同的算法以不同的方式实现这个接口，环境角色使用这个接口调用不同的算法</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">AbstractStrategy</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="keyword">virtual</span> ~AbstractStrategy() &#123;&#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">StrategyMethod</span><span class="params">()</span> </span>= <span class="number">0</span>;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">/// @brief 具体策略类, 实现了抽象策略定义的接口，提供具体的算法实现</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">ConcreteStrategyA</span> :</span> <span class="keyword">public</span> AbstractStrategy &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">StrategyMethod</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">"this is ConcreteStrategyA::StrategyMethod!\n"</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">ConcreteStrategyB</span> :</span> <span class="keyword">public</span> AbstractStrategy &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">StrategyMethod</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">"this is ConcreteStrategyB::StrategyMethod!\n"</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">/// @brief 环境类, 持有一个策略类的引用，最终给客户端调用</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Context</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">SetStrategy</span><span class="params">(AbstractStrategy* strategy)</span> </span>&#123;</span><br><span class="line">        strategy_ = strategy;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">StrategyMethod</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (strategy_) strategy_-&gt;StrategyMethod();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line">    AbstractStrategy* strategy_ = <span class="literal">nullptr</span>;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">&#125; <span class="comment">// namespace strategy</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">Test_14_strategy_impl_1</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">"-------------------- %s --------------------\n"</span>, __FUNCTION__);</span><br><span class="line">    strategy::AbstractStrategy* ptr_strategy_A = <span class="keyword">new</span> strategy::ConcreteStrategyA();</span><br><span class="line">    strategy::AbstractStrategy* ptr_strategy_B = <span class="keyword">new</span> strategy::ConcreteStrategyB();</span><br><span class="line"></span><br><span class="line">    strategy::Context env_;</span><br><span class="line">    env_.SetStrategy(ptr_strategy_A);</span><br><span class="line">    env_.StrategyMethod();</span><br><span class="line"></span><br><span class="line">    env_.SetStrategy(ptr_strategy_B);</span><br><span class="line">    env_.StrategyMethod();</span><br><span class="line"></span><br><span class="line">    <span class="keyword">delete</span> ptr_strategy_A;</span><br><span class="line">    <span class="keyword">delete</span> ptr_strategy_B;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// -------------------- Test_14_strategy_impl_1 --------------------</span></span><br><span class="line"><span class="comment">// this is ConcreteStrategyA::StrategyMethod!</span></span><br><span class="line"><span class="comment">// this is ConcreteStrategyB::StrategyMethod!</span></span><br></pre></td></tr></table></figure>
</li>
</ul>
<h3 id="行为型-命令"><a class="markdownIt-Anchor" href="#行为型-命令"></a> 行为型 - 命令</h3>
<ul>
<li>
<p>含义</p>
<p><code>Command</code> <strong>将一个请求封装为一个对象</strong>，使发出请求的责任和执行请求的责任分割开。</p>
<ul>
<li>优点
<ul>
<li><strong>降低系统的耦合度</strong>。命令模式能将调用操作的对象与实现该操作的对象解耦。</li>
<li><strong>增加或删除命令非常方便</strong>。采用命令模式增加与删除命令不会影响其他类，它满足“开闭原则”，对扩展比较灵活。</li>
<li>可以实现宏命令。命令模式<strong>可以与<code>组合模式</code>结合，将多个命令装配成一个组合命令，即宏命令</strong>。</li>
<li><strong>方便实现 Undo 和 Redo 操作</strong>。命令模式可以与<code>备忘录模式</code>结合，实现命令的撤销与恢复。</li>
</ul>
</li>
<li>缺点
<ul>
<li><strong>可能产生大量具体命令类</strong>。因为计对每一个具体操作都需要设计一个具体命令类，这将增加系统的复杂性。</li>
</ul>
</li>
</ul>
</li>
<li>
<p>应用场景</p>
<ul>
<li>在软件开发系统中，<strong>常常出现“方法的请求者”与“方法的实现者”之间存在紧密的耦合关系</strong>。这不利于软件功能的扩展与维护。例如，想对行为进行“撤销、重做、记录”等处理都很不方便。</li>
<li>在现实生活中，这样的例子也很多，例如，电视机遥控器（命令发送者）通过按钮（具体命令）来遥控电视机（命令接收者），还有计算机键盘上的“功能键”等。</li>
</ul>
</li>
<li>
<p>示例</p>
<ul>
<li>
<p>简单调用</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br></pre></td><td class="code"><pre><span class="line">  <span class="meta">#<span class="meta-keyword">pragma</span> once</span></span><br><span class="line">  </span><br><span class="line">  <span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;iostream&gt;</span></span></span><br><span class="line">  </span><br><span class="line">  <span class="keyword">namespace</span> command &#123;</span><br><span class="line">      </span><br><span class="line">  <span class="comment">/// @brief 抽象命令类, 声明执行命令的接口</span></span><br><span class="line">  <span class="class"><span class="keyword">class</span> <span class="title">AbstractCommand</span> &#123;</span></span><br><span class="line">  <span class="keyword">public</span>:</span><br><span class="line">      <span class="keyword">virtual</span> ~AbstractCommand() &#123;&#125;</span><br><span class="line">      <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Execute</span><span class="params">()</span> </span>= <span class="number">0</span>;</span><br><span class="line">  &#125;;</span><br><span class="line">  </span><br><span class="line">  <span class="comment">/// @brief 命令接收者, 执行命令功能的相关操作，是具体命令对象业务的真正实现者</span></span><br><span class="line">  <span class="class"><span class="keyword">class</span> <span class="title">Receiver</span> &#123;</span></span><br><span class="line">  <span class="keyword">public</span>:</span><br><span class="line">      <span class="function"><span class="keyword">void</span> <span class="title">Action</span><span class="params">()</span> </span>&#123;</span><br><span class="line">          <span class="built_in">printf</span>(<span class="string">"this is Receiver::Action!\n"</span>);</span><br><span class="line">      &#125;</span><br><span class="line">  &#125;;</span><br><span class="line">  </span><br><span class="line">  <span class="comment">/// @brief 具体命令类, 它拥有接收者对象，并通过调用接收者的功能来完成命令要执行的操作</span></span><br><span class="line">  <span class="class"><span class="keyword">class</span> <span class="title">ConcreteCommand</span> :</span> <span class="keyword">public</span> AbstractCommand &#123;</span><br><span class="line">  <span class="keyword">public</span>:</span><br><span class="line">      ConcreteCommand() &#123;</span><br><span class="line">          receiver_.reset(<span class="keyword">new</span> Receiver());</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Execute</span><span class="params">()</span> </span>&#123;</span><br><span class="line">          receiver_-&gt;Action();</span><br><span class="line">      &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="keyword">private</span>:</span><br><span class="line">      <span class="built_in">std</span>::<span class="built_in">shared_ptr</span>&lt;Receiver&gt; receiver_;</span><br><span class="line">  &#125;;</span><br><span class="line">  </span><br><span class="line">  <span class="comment">/// @brief 命令请求者, 请求的发送者，它通常拥有很多的命令对象，并通过访问命令对象来执行相关请求，它不直接访问接收者</span></span><br><span class="line">  <span class="class"><span class="keyword">class</span> <span class="title">Invoker</span>&#123;</span></span><br><span class="line">  <span class="keyword">public</span>:</span><br><span class="line">      Invoker(AbstractCommand* cmd) : cmd_(cmd) &#123;&#125;</span><br><span class="line">      <span class="function"><span class="keyword">void</span> <span class="title">SetCommand</span><span class="params">(AbstractCommand* cmd)</span> </span>&#123;</span><br><span class="line">          cmd_ = cmd;</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="function"><span class="keyword">void</span> <span class="title">Request</span><span class="params">()</span> </span>&#123;</span><br><span class="line">          cmd_-&gt;Execute();</span><br><span class="line">      &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="keyword">private</span>:</span><br><span class="line">      AbstractCommand* cmd_;</span><br><span class="line">  &#125;;</span><br><span class="line">  </span><br><span class="line">  &#125; <span class="comment">// namespace command</span></span><br><span class="line">  </span><br><span class="line">  <span class="function"><span class="keyword">void</span> <span class="title">Test_15_command_impl_1</span><span class="params">()</span> </span>&#123;</span><br><span class="line">      <span class="built_in">printf</span>(<span class="string">"-------------------- %s --------------------\n"</span>, __FUNCTION__);</span><br><span class="line">      <span class="built_in">std</span>::<span class="built_in">shared_ptr</span>&lt;command::AbstractCommand&gt; cmd(<span class="keyword">new</span> command::ConcreteCommand());</span><br><span class="line">  </span><br><span class="line">    command::<span class="function">Invoker <span class="title">client</span><span class="params">(cmd.get())</span></span>;</span><br><span class="line">      client.Request();</span><br><span class="line">&#125;</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// -------------------- Test_15_command_impl_1 --------------------</span></span><br><span class="line">  <span class="comment">// this is Receiver::Action!</span></span><br></pre></td></tr></table></figure>
</li>
<li>
<p>与<code>组合模式</code>结合, 实现<strong>宏命令</strong></p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">pragma</span> once</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;vector&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> command &#123;</span><br><span class="line">    </span><br><span class="line"><span class="comment">/// 命令模式 + 组合模式 = 宏命令</span></span><br><span class="line"><span class="comment">/// 宏命令包含了一组命令，它充当了具体命令与调用者的双重角色，执行它时将递归调用它所包含的所有命令</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/// @brief 抽象命令类, 声明执行命令的接口</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">AbstractMacroCommand</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="keyword">virtual</span> ~AbstractMacroCommand() &#123;&#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Execute</span><span class="params">()</span> </span>= <span class="number">0</span>;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">/// @brief 命令接收者, 执行命令功能的相关操作，是具体命令对象业务的真正实现者</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">CompositeReceiver</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">ActionA</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">"this is CompositeReceiver::ActionA!\n"</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">ActionB</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">"this is CompositeReceiver::ActionB!\n"</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">/// @brief 具体命令类, 它拥有接收者对象，并通过调用接收者的功能来完成命令要执行的操作</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">ConcreteCommandA</span> :</span> <span class="keyword">public</span> AbstractMacroCommand &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    ConcreteCommandA() &#123;</span><br><span class="line">        receiver_.reset(<span class="keyword">new</span> CompositeReceiver());</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Execute</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        receiver_-&gt;ActionA();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line">    <span class="built_in">std</span>::<span class="built_in">shared_ptr</span>&lt;CompositeReceiver&gt; receiver_;</span><br><span class="line">&#125;;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">ConcreteCommandB</span> :</span> <span class="keyword">public</span> AbstractMacroCommand &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    ConcreteCommandB() &#123;</span><br><span class="line">        receiver_.reset(<span class="keyword">new</span> CompositeReceiver());</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Execute</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        receiver_-&gt;ActionB();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line">    <span class="built_in">std</span>::<span class="built_in">shared_ptr</span>&lt;CompositeReceiver&gt; receiver_;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">/// @brief 命令请求者, 请求的发送者，它通常拥有很多的命令对象，并通过访问命令对象来执行相关请求，它不直接访问接收者</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">CompositeInvoker</span>&#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">AddCommand</span><span class="params">(AbstractMacroCommand* cmd)</span> </span>&#123;</span><br><span class="line">        cmds_.emplace_back(cmd);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">RemoveCommand</span><span class="params">(AbstractMacroCommand* cmd)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">auto</span> it = cmds_.begin(); it != cmds_.end(); it++) &#123;</span><br><span class="line">            <span class="keyword">if</span> (cmd == (*it)) &#123;</span><br><span class="line">                cmds_.erase(it++);</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">Request</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">auto</span>* cmd : cmds_) &#123;</span><br><span class="line">            cmd-&gt;Execute();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line">    <span class="built_in">std</span>::<span class="built_in">vector</span>&lt;AbstractMacroCommand*&gt; cmds_;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">&#125; <span class="comment">// namespace command</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">Test_15_command_impl_2</span><span class="params">()</span> </span>&#123;</span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">"-------------------- %s --------------------\n"</span>, __FUNCTION__);</span><br><span class="line">    <span class="built_in">std</span>::<span class="built_in">shared_ptr</span>&lt;command::AbstractMacroCommand&gt; cmd_A(<span class="keyword">new</span> command::ConcreteCommandA());</span><br><span class="line">    <span class="built_in">std</span>::<span class="built_in">shared_ptr</span>&lt;command::AbstractMacroCommand&gt; cmd_B(<span class="keyword">new</span> command::ConcreteCommandB());</span><br><span class="line"></span><br><span class="line">    command::CompositeInvoker client;</span><br><span class="line">    client.AddCommand(cmd_A.get());</span><br><span class="line">    client.AddCommand(cmd_B.get());</span><br><span class="line">    </span><br><span class="line">    client.Request();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// -------------------- Test_15_command_impl_2 --------------------</span></span><br><span class="line"><span class="comment">// this is CompositeReceiver::ActionA!</span></span><br><span class="line"><span class="comment">// this is CompositeReceiver::ActionB!</span></span><br></pre></td></tr></table></figure>
</li>
<li>
<p>与<code>备忘录模式</code>结合, 实现<strong>命令的撤销与恢复</strong></p>
</li>
</ul>
</li>
</ul>
<h3 id="行为型-责任链"><a class="markdownIt-Anchor" href="#行为型-责任链"></a> 行为型 - 责任链</h3>
<ul>
<li>
<p>含义</p>
<p><code>Chain of Responsibility</code> <strong>把请求从链中的一个对象传到下一个对象，直到请求被响应为止</strong>。通过这种方式去除对象之间的耦合。</p>
<p>注: 责任链模式也叫<strong>职责链模式</strong>。</p>
<ul>
<li>优点
<ul>
<li><strong>降低了对象之间的耦合度</strong>。该模式使得一个对象无须知道到底是哪一个对象处理其请求以及链的结构，发送者和接收者也无须拥有对方的明确信息。</li>
<li>增强了系统的<strong>可扩展性</strong>。可以根据需要增加新的请求处理类，<strong>满足开闭原则</strong>。</li>
<li>增强了给对象指派职责的<strong>灵活性</strong>。当工作流程发生变化，可以动态地改变链内的成员或者调动它们的次序，也可动态地新增或者删除责任。</li>
<li>责任链简化了对象之间的连接。<strong>每个对象只需保持一个指向其后继者的引用</strong>，不需保持其他所有处理者的引用，这避免了使用众多的 if 或者 if···else 语句。</li>
<li>责任分担。每个类只需要处理自己该处理的工作，不该处理的传递给下一个对象完成，明确各类的责任范围，<strong>符合类的单一职责原则</strong>。</li>
</ul>
</li>
<li>缺点
<ul>
<li><strong>不能保证每个请求一定被处理</strong>。由于一个请求没有明确的接收者，该请求可能一直传到链的末端都得不到处理。</li>
<li>对比较长的职责链，请求的处理可能涉及多个处理对象，<strong>系统性能将受到一定影响</strong>。</li>
<li>职责链建立的<strong>合理性要靠客户端来保证</strong>，增加了客户端的复杂性，可能会由于职责链的错误设置而导致系统出错，如可能会造成循环调用。</li>
</ul>
</li>
</ul>
</li>
<li>
<p>应用场景</p>
<ul>
<li>在现实生活中，常常会出现这样的事例：<strong>一个请求有多个对象可以处理，但每个对象的处理条件或权限不同</strong>。例如，公司员工请假，可批假的领导有部门负责人、副总经理、总经理等，但每个领导能批准的天数不同，员工必须根据自己要请假的天数去找不同的领导签名，也就是说员工必须记住每个领导的姓名、电话和地址等信息，这增加了难度。</li>
<li>在计算机软硬件中也有相关例子，如总线网中数据报传送，每台计算机根据目标地址是否同自己的地址相同来决定是否接收；还有异常处理中，处理程序根据异常的类型决定自己是否处理该异常等。</li>
</ul>
</li>
<li>
<p>示例</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">pragma</span> once</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;string&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> responsibility &#123;</span><br><span class="line">    </span><br><span class="line"><span class="comment">/// @brief 抽象处理者, 定义一个处理请求的接口，包含抽象处理方法和一个后继连接</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">AbstractHandler</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="keyword">virtual</span> ~AbstractHandler() &#123;&#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">SetNext</span><span class="params">(AbstractHandler* handler)</span> </span>&#123;</span><br><span class="line">        next_ = handler;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> AbstractHandler* <span class="title">GetNext</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> next_;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Request</span><span class="params">(<span class="keyword">const</span> <span class="built_in">std</span>::<span class="built_in">string</span>&amp; state)</span> </span>= <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line">    AbstractHandler* next_ = <span class="literal">nullptr</span>;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">/// @brief 具体处理者, 实现抽象处理者的处理方法，判断能否处理本次请求，如果可以处理请求则处理，否则将该请求转给它的后继者</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">ConcreteHandlerA</span> :</span> <span class="keyword">public</span> AbstractHandler &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Request</span><span class="params">(<span class="keyword">const</span> <span class="built_in">std</span>::<span class="built_in">string</span>&amp; state)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (<span class="number">0</span> == state.compare(<span class="string">"A"</span>)) &#123;</span><br><span class="line">            <span class="built_in">printf</span>(<span class="string">"this is ConcreteHandlerA::Request!\n"</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="keyword">if</span> (GetNext()) &#123;</span><br><span class="line">                GetNext()-&gt;Request(state);</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">else</span> &#123;</span><br><span class="line">                <span class="built_in">printf</span>(<span class="string">"From A, Nobody handle this request!\n"</span>);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">ConcreteHandlerB</span> :</span> <span class="keyword">public</span> AbstractHandler &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Request</span><span class="params">(<span class="keyword">const</span> <span class="built_in">std</span>::<span class="built_in">string</span>&amp; state)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (<span class="number">0</span> == state.compare(<span class="string">"B"</span>)) &#123;</span><br><span class="line">            <span class="built_in">printf</span>(<span class="string">"this is ConcreteHandlerB::Request!\n"</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="keyword">if</span> (!GetNext()) &#123;</span><br><span class="line">                GetNext()-&gt;Request(state);</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">else</span> &#123;</span><br><span class="line">                <span class="built_in">printf</span>(<span class="string">"From B, Nobody handle this request!\n"</span>);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">&#125; <span class="comment">// namespace responsibility</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">Test_16_chain_of_responsibility_impl_1</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">"-------------------- %s --------------------\n"</span>, __FUNCTION__);</span><br><span class="line">    <span class="built_in">std</span>::<span class="built_in">shared_ptr</span>&lt;responsibility::AbstractHandler&gt; ptr_A(<span class="keyword">new</span> responsibility::ConcreteHandlerA());</span><br><span class="line">    <span class="built_in">std</span>::<span class="built_in">shared_ptr</span>&lt;responsibility::AbstractHandler&gt; ptr_B(<span class="keyword">new</span> responsibility::ConcreteHandlerB());</span><br><span class="line"></span><br><span class="line">    ptr_A-&gt;SetNext(ptr_B.get());</span><br><span class="line">    ptr_A-&gt;Request(<span class="string">"B"</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// -------------------- Test_16_chain_of_responsibility_impl_1 --------------------</span></span><br><span class="line"><span class="comment">// this is ConcreteHandlerB::Request!</span></span><br></pre></td></tr></table></figure>
</li>
</ul>
<h3 id="行为型-状态"><a class="markdownIt-Anchor" href="#行为型-状态"></a> 行为型 - 状态</h3>
<ul>
<li>
<p>含义</p>
<p><code>State</code> <strong>允许一个对象在其内部状态发生改变时改变其行为能力</strong>。</p>
<p>​	在软件开发过程中，<strong>应用程序中的有些对象可能会根据不同的情况做出不同的行为</strong>，我们把这种对象称为有状态的对象，而把影响对象行为的一个或多个动态变化的属性称为状态。当有状态的对象与外部事件产生互动时，其内部状态会发生改变，从而使得其行为也随之发生改变。如人的情绪有高兴的时候和伤心的时候，不同的情绪有不同的行为，当然外界也会影响其情绪变化。</p>
<p>​	对这种有状态的对象编程，<strong>传统的解决方案是：将这些所有可能发生的情况全都考虑到，然后使用 if-else 语句来做状态判断，再进行不同情况的处理</strong>。但当对象的状态很多时，程序会变得很复杂。而且增加新的状态要添加新的 if-else 语句，这违背了“开闭原则”，不利于程序的扩展。</p>
<ul>
<li>优点
<ul>
<li>状态模式将与特定状态相关的行为局部化到一个状态中，并且将不同状态的行为分割开来，<strong>满足“单一职责原则”</strong>。</li>
<li><strong>减少对象间的相互依赖</strong>。将不同的状态引入独立的对象中会使得状态转换变得更加明确，且减少对象间的相互依赖。</li>
<li>有<strong>利于程序的扩展</strong>。通过定义新的子类很容易地增加新的状态和转换。</li>
</ul>
</li>
<li>缺点
<ul>
<li>状态模式的使用必然会增加系统的类与对象的个数</li>
</ul>
</li>
</ul>
</li>
<li>
<p>应用场景</p>
<ul>
<li>当一个对象的行为取决于它的状态，并且它<strong>必须在运行时根据状态改变它的行为时</strong>。</li>
<li>一个操作中含有庞大的分支结构，并且这些分支决定于对象的状态时。</li>
</ul>
</li>
<li>
<p>示例</p>
<ul>
<li>
<p>开关状态</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">pragma</span> once</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;iostream&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> state &#123;</span><br><span class="line">    </span><br><span class="line"><span class="comment">/// @brief 环境类, 定义了客户感兴趣的接口，维护一个当前状态，并将与状态相关的操作委托给当前状态对象来处理</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">AbstractState</span>;</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">EnvContext</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    EnvContext();</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">SetState</span><span class="params">(<span class="built_in">std</span>::<span class="built_in">shared_ptr</span>&lt;AbstractState&gt;&amp; state)</span> </span>&#123;</span><br><span class="line">        state_ = state;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="built_in">std</span>::<span class="built_in">shared_ptr</span>&lt;AbstractState&gt;&amp; GetState() &#123;</span><br><span class="line">        <span class="keyword">return</span> state_;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">Operation</span><span class="params">()</span></span>;</span><br><span class="line">    </span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line">    <span class="built_in">std</span>::<span class="built_in">shared_ptr</span>&lt;AbstractState&gt; state_ = <span class="literal">nullptr</span>;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">/// @brief 抽象状态类, 封装环境对象中的特定状态所对应的行为</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">AbstractState</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="keyword">virtual</span> ~AbstractState() &#123;&#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Operation</span><span class="params">(EnvContext* context)</span> </span>= <span class="number">0</span>;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">/// @brief 具体状态类, 实现抽象状态所对应的行为</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">ConcreteStateA</span> :</span> <span class="keyword">public</span> AbstractState &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Operation</span><span class="params">(EnvContext* context)</span></span>;</span><br><span class="line">&#125;;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">ConcreteStateB</span> :</span> <span class="keyword">public</span> AbstractState &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Operation</span><span class="params">(EnvContext* context)</span></span>;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">EnvContext::EnvContext() &#123;</span><br><span class="line">    state_.reset(<span class="keyword">new</span> ConcreteStateA()); <span class="comment">// 给定初始状态</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">void</span> EnvContext::Operation() &#123;</span><br><span class="line">    state_-&gt;Operation(<span class="keyword">this</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">void</span> ConcreteStateA::Operation(EnvContext* context) &#123;</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">"Now Your State is A!\n"</span>);</span><br><span class="line">    <span class="comment">// 同时改变状态</span></span><br><span class="line">    <span class="built_in">std</span>::<span class="built_in">shared_ptr</span>&lt;AbstractState&gt; new_state(<span class="keyword">new</span> ConcreteStateB());</span><br><span class="line">    context-&gt;SetState(new_state);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">void</span> ConcreteStateB::Operation(EnvContext* context) &#123;</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">"Now Your State is B!\n"</span>);</span><br><span class="line">    <span class="comment">// 同时改变状态</span></span><br><span class="line">    <span class="built_in">std</span>::<span class="built_in">shared_ptr</span>&lt;AbstractState&gt; new_state(<span class="keyword">new</span> ConcreteStateA());</span><br><span class="line">    context-&gt;SetState(new_state);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">&#125; <span class="comment">// namespace state</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">Test_17_state_impl_1</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">"-------------------- %s --------------------\n"</span>, __FUNCTION__);</span><br><span class="line">    <span class="built_in">std</span>::<span class="built_in">shared_ptr</span>&lt;state::EnvContext&gt; ptr(<span class="keyword">new</span> state::EnvContext());</span><br><span class="line">    ptr-&gt;Operation();   <span class="comment">// A</span></span><br><span class="line">    ptr-&gt;Operation();   <span class="comment">// B</span></span><br><span class="line">    ptr-&gt;Operation();   <span class="comment">// A</span></span><br><span class="line">    ptr-&gt;Operation();   <span class="comment">// B</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// -------------------- Test_17_state_impl_1 --------------------</span></span><br><span class="line"><span class="comment">// Now Your State is A!</span></span><br><span class="line"><span class="comment">// Now Your State is B!</span></span><br><span class="line"><span class="comment">// Now Your State is A!</span></span><br><span class="line"><span class="comment">// Now Your State is B!</span></span><br></pre></td></tr></table></figure>
</li>
</ul>
</li>
</ul>
<h3 id="行为型-观察者"><a class="markdownIt-Anchor" href="#行为型-观察者"></a> 行为型 - 观察者</h3>
<ul>
<li>
<p>含义</p>
<p><code>Observer</code> <strong>多个对象间存在一对多关系，当一个对象发生改变时，把这种改变通知给其他多个对象，从而影响其他对象的行为</strong>。</p>
<p>​	在现实世界中，许多对象并不是独立存在的，其中一个对象的行为发生改变可能会导致一个或者多个其他对象的行为也发生改变。例如，某种商品的物价上涨时会导致部分商家高兴，而消费者伤心；还有，当我们开车到交叉路口时，遇到红灯会停，遇到绿灯会行。这样的例子还有很多，例如，股票价格与股民、微信公众号与微信用户、气象局的天气预报与听众、小偷与警察等。</p>
<p>​	在软件世界也是这样，例如，Excel 中的数据与折线图、饼状图、柱状图之间的关系；MVC 模式中的模型与视图的关系；事件模型中的事件源与事件处理者。</p>
<ul>
<li>优点
<ul>
<li>降低了目标与观察者之间的耦合关系，两者之间是抽象耦合关系。</li>
<li>目标与观察者之间建立了一套触发机制。</li>
</ul>
</li>
<li>缺点
<ul>
<li>目标与观察者之间的依赖关系并没有完全解除，而且有可能出现循环引用。</li>
<li>当观察者对象很多时，通知的发布会花费很多时间，影响程序的效率。</li>
</ul>
</li>
</ul>
</li>
<li>
<p>应用场景</p>
<ul>
<li>对象间<strong>存在一对多关系</strong>，<strong>一个对象的状态发生改变会影响其他对象</strong>。</li>
<li>当一个抽象模型有两个方面，其中一个方面依赖于另一方面时，可将这二者封装在独立的对象中以使它们可以各自独立地改变和复用。</li>
</ul>
</li>
<li>
<p>示例</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">pragma</span> once</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;vector&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> observer &#123;</span><br><span class="line"></span><br><span class="line"><span class="comment">/// @brief 抽象观察者, 包含了一个更新自己的抽象方法，当接到具体主题的更改通知时被调用。</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">AbstractObserver</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    ~AbstractObserver() &#123;&#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 被告知时做出响应</span></span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Response</span><span class="params">()</span> </span>= <span class="number">0</span>;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">/// @brief 具体观察者, 实现抽象观察者中定义的抽象方法，以便在得到目标的更改通知时更新自身的状态。</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">ConcreteObserverA</span> :</span> <span class="keyword">public</span> AbstractObserver &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Response</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">"this is ConcreteObserverA::Response!\n"</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">ConcreteObserverB</span> :</span> <span class="keyword">public</span> AbstractObserver &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Response</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">"this is ConcreteObserverB::Response!\n"</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">/// @brief 抽象主题类, 它提供了一个用于保存观察者对象的聚集类和增加、删除观察者对象的方法，以及通知所有观察者的抽象方法</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">AbstractSubject</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="keyword">virtual</span> ~AbstractSubject() &#123;&#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">NotifyObserver</span><span class="params">()</span> </span>= <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">AddObserver</span><span class="params">(AbstractObserver* observer)</span> </span>&#123;</span><br><span class="line">        observers_.emplace_back(observer);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">RemoveObserver</span><span class="params">(AbstractObserver* observer)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">auto</span> it = observers_.begin(); it != observers_.end(); it++) &#123;</span><br><span class="line">            <span class="keyword">if</span> ((*it) == observer) &#123;</span><br><span class="line">                observers_.erase(it++);</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">protected</span>:</span><br><span class="line">    <span class="built_in">std</span>::<span class="built_in">vector</span>&lt;AbstractObserver*&gt; observers_;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">/// @brief 具体主题类, 它实现抽象目标中的通知方法，当具体主题的内部状态发生改变时，通知所有注册过的观察者对象。</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">ConcreteSubject</span> :</span> <span class="keyword">public</span> AbstractSubject &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">NotifyObserver</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">auto</span>* observer : observers_) &#123;</span><br><span class="line">            observer-&gt;Response();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line">    </span><br><span class="line">&#125; <span class="comment">// namespace observer</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">Test_18_observer_impl_1</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">"-------------------- %s --------------------\n"</span>, __FUNCTION__);</span><br><span class="line">    <span class="built_in">std</span>::<span class="built_in">shared_ptr</span>&lt;observer::AbstractSubject&gt; ptr_subject(<span class="keyword">new</span> observer::ConcreteSubject());</span><br><span class="line">    <span class="built_in">std</span>::<span class="built_in">shared_ptr</span>&lt;observer::AbstractObserver&gt; ptr_observer_A(<span class="keyword">new</span> observer::ConcreteObserverA());</span><br><span class="line">    <span class="built_in">std</span>::<span class="built_in">shared_ptr</span>&lt;observer::AbstractObserver&gt; ptr_observer_B(<span class="keyword">new</span> observer::ConcreteObserverB());</span><br><span class="line"></span><br><span class="line">    ptr_subject-&gt;AddObserver(ptr_observer_A.get());</span><br><span class="line">    ptr_subject-&gt;AddObserver(ptr_observer_B.get());</span><br><span class="line"></span><br><span class="line">    ptr_subject-&gt;NotifyObserver();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// -------------------- Test_18_observer_impl_1 --------------------</span></span><br><span class="line"><span class="comment">// this is ConcreteObserverA::Response!</span></span><br><span class="line"><span class="comment">// this is ConcreteObserverB::Response!</span></span><br></pre></td></tr></table></figure>
</li>
</ul>
<h3 id="行为型-中介者"><a class="markdownIt-Anchor" href="#行为型-中介者"></a> 行为型 - 中介者</h3>
<ul>
<li>
<p>含义</p>
<p><code>Mediator</code> 定义一个中介对象来简化原有对象之间的交互关系，降低系统中对象间的耦合度，使原有对象之间不必相互了解。</p>
<ul>
<li>优点
<ul>
<li>降低了对象之间的耦合性，使得对象易于独立地被复用。</li>
<li>将对象间的一对多关联转变为一对一的关联，提高系统的灵活性，使得系统易于维护和扩展。</li>
</ul>
</li>
<li>缺点
<ul>
<li>当同事类太多时，中介者的职责将很大，它会变得复杂而庞大，以至于系统难以维护。</li>
</ul>
</li>
</ul>
</li>
<li>
<p>应用场景</p>
<ul>
<li>当对象之间存在<strong>复杂的网状结构关系</strong>而导致依赖关系混乱且难以复用时。</li>
<li>当<strong>想创建一个运行于多个类之间的对象</strong>，又不想生成新的子类时。</li>
</ul>
</li>
<li>
<p>示例</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">pragma</span> once</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;list&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> mediator &#123;</span><br><span class="line">    </span><br><span class="line"><span class="comment">/// @brief 抽象同事类, 定义同事类的接口，保存中介者对象，提供同事对象交互的抽象方法，实现所有相互影响的同事类的公共功能</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">AbstractMediator</span>;</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">AbstractColleague</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="keyword">virtual</span> ~AbstractColleague() &#123;&#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/// @brief 抽象接口</span></span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Receive</span><span class="params">()</span> </span>= <span class="number">0</span>;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Send</span><span class="params">()</span> </span>= <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/// @brief 设置中介对象</span></span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">SetMedium</span><span class="params">(AbstractMediator* mediator)</span> </span>&#123;</span><br><span class="line">        mediator_ = mediator;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">protected</span>:</span><br><span class="line">    AbstractMediator* mediator_ = <span class="literal">nullptr</span>;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">/// @brief 具体同事类, 抽象同事类的实现者，当需要与其他同事对象交互时，由中介者对象负责后续的交互</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">ConcreteColleagueA</span> :</span> <span class="keyword">public</span> AbstractColleague &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Receive</span><span class="params">()</span></span>;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Send</span><span class="params">()</span></span>;</span><br><span class="line">&#125;;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">ConcreteColleagueB</span> :</span> <span class="keyword">public</span> AbstractColleague &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Receive</span><span class="params">()</span></span>;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Send</span><span class="params">()</span></span>;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">/// @brief 抽象中介类, 中介者的接口，提供了同事对象注册与转发同事对象信息的抽象方法</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">AbstractMediator</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="keyword">virtual</span> ~AbstractMediator() &#123;&#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/// @brief 注册</span></span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Register</span><span class="params">(AbstractColleague* colleague)</span> </span>= <span class="number">0</span>;</span><br><span class="line">    <span class="comment">/// @brief 转发</span></span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Relay</span><span class="params">(AbstractColleague* colleague)</span> </span>= <span class="number">0</span>;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">/// @brief 具体中介类, 实现中介者接口. 管理同事对象，协调各个同事角色之间的交互关系，依赖于同事角色</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">ConcreteMediator</span> :</span> <span class="keyword">public</span> AbstractMediator &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Register</span><span class="params">(AbstractColleague* colleague)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">auto</span>* c : colleagues_) &#123;</span><br><span class="line">            <span class="keyword">if</span> (c == colleague) <span class="keyword">return</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        colleagues_.emplace_back(colleague);</span><br><span class="line">        colleague-&gt;SetMedium(<span class="keyword">this</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Relay</span><span class="params">(AbstractColleague* colleague)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">auto</span>* c : colleagues_) &#123;</span><br><span class="line">            <span class="comment">// 转发给除自己外的同事</span></span><br><span class="line">            <span class="keyword">if</span> (c != colleague) c-&gt;Receive();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line">    <span class="built_in">std</span>::<span class="built_in">list</span>&lt;AbstractColleague*&gt; colleagues_;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">///////////////////////////////////////////////////////// 同事类实现</span></span><br><span class="line"><span class="keyword">void</span> ConcreteColleagueA::Receive() &#123;</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">"this is ConcreteColleagueA::Receive!\n"</span>);</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">void</span> ConcreteColleagueA::Send() &#123;</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">"this is ConcreteColleagueA::Send!\n"</span>);</span><br><span class="line">    <span class="comment">// 请中介者转发</span></span><br><span class="line">    mediator_-&gt;Relay(<span class="keyword">this</span>);</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">void</span> ConcreteColleagueB::Receive() &#123;</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">"this is ConcreteColleagueB::Receive!\n"</span>);</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">void</span> ConcreteColleagueB::Send() &#123;</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">"this is ConcreteColleagueB::Send!\n"</span>);</span><br><span class="line">    <span class="comment">// 请中介者转发</span></span><br><span class="line">    mediator_-&gt;Relay(<span class="keyword">this</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">&#125; <span class="comment">// namespace mediator</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">Test_19_mediator_impl_1</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">"-------------------- %s --------------------\n"</span>, __FUNCTION__);</span><br><span class="line">    <span class="built_in">std</span>::<span class="built_in">shared_ptr</span>&lt;mediator::AbstractMediator&gt; ptr_md(<span class="keyword">new</span> mediator::ConcreteMediator());</span><br><span class="line"></span><br><span class="line">    <span class="built_in">std</span>::<span class="built_in">shared_ptr</span>&lt;mediator::AbstractColleague&gt; ptr_c1(<span class="keyword">new</span> mediator::ConcreteColleagueA());</span><br><span class="line">    <span class="built_in">std</span>::<span class="built_in">shared_ptr</span>&lt;mediator::AbstractColleague&gt; ptr_c2(<span class="keyword">new</span> mediator::ConcreteColleagueB());</span><br><span class="line"></span><br><span class="line">    ptr_md-&gt;Register(ptr_c1.get());</span><br><span class="line">    ptr_md-&gt;Register(ptr_c2.get());</span><br><span class="line"></span><br><span class="line">    ptr_c1-&gt;Send();</span><br><span class="line"></span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">"-----------\n"</span>);</span><br><span class="line"></span><br><span class="line">    ptr_c2-&gt;Send();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// -------------------- Test_19_mediator_impl_1 --------------------</span></span><br><span class="line"><span class="comment">// this is ConcreteColleagueA::Send!</span></span><br><span class="line"><span class="comment">// this is ConcreteColleagueB::Receive!</span></span><br><span class="line"><span class="comment">// -----------</span></span><br><span class="line"><span class="comment">// this is ConcreteColleagueB::Send!</span></span><br><span class="line"><span class="comment">// this is ConcreteColleagueA::Receive!</span></span><br></pre></td></tr></table></figure>
</li>
</ul>
<h3 id="行为型-迭代器"><a class="markdownIt-Anchor" href="#行为型-迭代器"></a> 行为型 - 迭代器</h3>
<ul>
<li>
<p>含义</p>
<p><code>Iterator</code> 提供一种方法来<strong>顺序访问聚合对象中的一系列数据</strong>，而<strong>不暴露聚合对象的内部表示</strong>。</p>
<ul>
<li>优点
<ul>
<li>访问一个聚合对象的内容而无须暴露它的内部表示。</li>
<li>遍历任务交由迭代器完成，这简化了聚合类。</li>
<li>它支持以不同方式遍历一个聚合，甚至可以自定义迭代器的子类以支持新的遍历。</li>
<li>增加新的聚合类和迭代器类都很方便，无须修改原有代码。</li>
<li>封装性良好，为遍历不同的聚合结构提供一个统一的接口。</li>
</ul>
</li>
<li>缺点
<ul>
<li>增加了类的个数，这在一定程度上增加了系统的复杂性。</li>
</ul>
</li>
</ul>
</li>
<li>
<p>应用场景</p>
</li>
<li>
<p>示例</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 直接使用 STL 即可.</span></span><br></pre></td></tr></table></figure>
</li>
</ul>
<h3 id="行为型-访问者"><a class="markdownIt-Anchor" href="#行为型-访问者"></a> 行为型 - 访问者</h3>
<ul>
<li>
<p>含义</p>
<p><code>Visitor</code> 在不改变集合元素的前提下，为一个集合中的每个元素提供多种访问方式，即每个元素有多个访问者对象访问。</p>
<ul>
<li>优点
<ul>
<li>扩展性好。<strong>能够在不修改对象结构中的元素的情况下，为对象结构中的元素添加新的功能。</strong></li>
<li>复用性好。<strong>可以通过访问者来定义整个对象结构通用的功能</strong>，从而提高系统的复用程度。</li>
<li>灵活性好。访问者模式<strong>将数据结构与作用于结构上的操作解耦</strong>，使得操作集合可相对自由地演化而不影响系统的数据结构。</li>
<li><strong>符合单一职责原则</strong>。访问者模式把相关的行为封装在一起，构成一个访问者，使每一个访问者的功能都比较单一。</li>
</ul>
</li>
<li>缺点
<ul>
<li>增加新的元素类很困难。在访问者模式中，<strong>每增加一个新的元素类，都要在每一个具体访问者类中增加相应的具体操作，这违背了“开闭原则”</strong>。</li>
<li>破坏封装。访问者模式中<strong>具体元素对访问者公布细节，这破坏了对象的封装性</strong>。</li>
<li>违反了依赖倒置原则。访问者模式<strong>依赖了具体类，而没有依赖抽象类</strong>。</li>
</ul>
</li>
</ul>
</li>
<li>
<p>应用场景</p>
<ul>
<li>对象结构相对稳定，但其<strong>操作算法经常变化</strong>的程序。</li>
<li><strong>对象结构中的对象需要提供多种不同且不相关的操作</strong>，而且要避免让这些操作的变化影响对象的结构。</li>
<li>对象结构包含很多类型的对象，希望对这些对象实施一些依赖于其具体类型的操作。</li>
</ul>
</li>
<li>
<p>示例</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">pragma</span> once</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;list&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> visitor &#123;</span><br><span class="line"></span><br><span class="line"><span class="comment">/// @brief 抽象访问者, 定义一个访问具体元素的接口，为每个具体元素类对应一个访问操作，该操作中的参数类型标识了被访问的具体元素。</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">ConcreteElementA</span>;</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">ConcreteElementB</span>;</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">AbstractVisitor</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="keyword">virtual</span> ~AbstractVisitor() &#123;&#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/// @brief 访问操作, 依赖于具体元素类</span></span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Visit</span><span class="params">(ConcreteElementA* element)</span> </span>= <span class="number">0</span>;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Visit</span><span class="params">(ConcreteElementB* element)</span> </span>= <span class="number">0</span>;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">/// @brief 具体访问者, 实现抽象访问者角色中声明的各个访问操作，确定访问者访问一个元素时该做什么。</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">ConcreteVisitorA</span> :</span> <span class="keyword">public</span> AbstractVisitor &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Visit</span><span class="params">(ConcreteElementA* element)</span></span>;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Visit</span><span class="params">(ConcreteElementB* element)</span></span>;</span><br><span class="line">&#125;;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">ConcreteVisitorB</span> :</span> <span class="keyword">public</span> AbstractVisitor &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Visit</span><span class="params">(ConcreteElementA* element)</span></span>;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Visit</span><span class="params">(ConcreteElementB* element)</span></span>;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">/// @brief 抽象元素, 声明一个包含接受操作 accept() 的接口，被接受的访问者对象作为 accept() 方法的参数</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">AbstractElement</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="keyword">virtual</span> ~AbstractElement() &#123;&#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Accept</span><span class="params">(AbstractVisitor* visitor)</span> </span>= <span class="number">0</span>;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">/// @brief 具体元素角色：实现抽象元素角色提供的 accept() 操作，另外具体元素中可能还包含本身业务逻辑的相关操作。</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">ConcreteElementA</span> :</span> <span class="keyword">public</span> AbstractElement &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Accept</span><span class="params">(AbstractVisitor* visitor)</span> </span>&#123;</span><br><span class="line">        visitor-&gt;Visit(<span class="keyword">this</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">OperatorA</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">"this is ConcreteElementA::OperatorA!\n"</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">ConcreteElementB</span> :</span> <span class="keyword">public</span> AbstractElement &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Accept</span><span class="params">(AbstractVisitor* visitor)</span> </span>&#123;</span><br><span class="line">        visitor-&gt;Visit(<span class="keyword">this</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">OperatorB</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">"this is ConcreteElementB::OperatorB!\n"</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">void</span> ConcreteVisitorA::Visit(ConcreteElementA* element) &#123;</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">"this is ConcreteVisitorA::Visit!\n"</span>);</span><br><span class="line">    element-&gt;OperatorA();</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">void</span> ConcreteVisitorA::Visit(ConcreteElementB* element) &#123;</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">"this is ConcreteVisitorA::Visit!\n"</span>);</span><br><span class="line">    element-&gt;OperatorB();</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">void</span> ConcreteVisitorB::Visit(ConcreteElementA* element) &#123;</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">"this is ConcreteVisitorB::Visit!\n"</span>);</span><br><span class="line">    element-&gt;OperatorA();</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">void</span> ConcreteVisitorB::Visit(ConcreteElementB* element) &#123;</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">"this is ConcreteVisitorB::Visit!\n"</span>);</span><br><span class="line">    element-&gt;OperatorB();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">&#125; <span class="comment">// namespace visitor</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">Test_20_visitor_impl_1</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">"-------------------- %s --------------------\n"</span>, __FUNCTION__);</span><br><span class="line">    <span class="built_in">std</span>::<span class="built_in">list</span>&lt;visitor::AbstractElement*&gt; elements;</span><br><span class="line">    elements.emplace_back(<span class="keyword">new</span> visitor::ConcreteElementA());</span><br><span class="line">    elements.emplace_back(<span class="keyword">new</span> visitor::ConcreteElementB());</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 为所有元素设置访问者A</span></span><br><span class="line">    <span class="built_in">std</span>::<span class="built_in">shared_ptr</span>&lt;visitor::AbstractVisitor&gt; ptr_visitor_a(<span class="keyword">new</span> visitor::ConcreteVisitorA());</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">auto</span>* e : elements) &#123;</span><br><span class="line">        e-&gt;Accept(ptr_visitor_a.get());</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">"----------------------\n"</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 为所有元素设置访问者B</span></span><br><span class="line">    <span class="built_in">std</span>::<span class="built_in">shared_ptr</span>&lt;visitor::AbstractVisitor&gt; ptr_visitor_b(<span class="keyword">new</span> visitor::ConcreteVisitorB());</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">auto</span>* e : elements) &#123;</span><br><span class="line">        e-&gt;Accept(ptr_visitor_b.get());</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">auto</span>* e : elements) &#123;</span><br><span class="line">        <span class="keyword">if</span> (e) <span class="keyword">delete</span> e;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// -------------------- Test_20_visitor_impl_1 --------------------</span></span><br><span class="line"><span class="comment">// this is ConcreteVisitorA::Visit!</span></span><br><span class="line"><span class="comment">// this is ConcreteElementA::OperatorA!</span></span><br><span class="line"><span class="comment">// this is ConcreteVisitorA::Visit!</span></span><br><span class="line"><span class="comment">// this is ConcreteElementB::OperatorB!</span></span><br><span class="line"><span class="comment">// ----------------------</span></span><br><span class="line"><span class="comment">// this is ConcreteVisitorB::Visit!</span></span><br><span class="line"><span class="comment">// this is ConcreteElementA::OperatorA!</span></span><br><span class="line"><span class="comment">// this is ConcreteVisitorB::Visit!</span></span><br><span class="line"><span class="comment">// this is ConcreteElementB::OperatorB!</span></span><br></pre></td></tr></table></figure>
</li>
</ul>
<h3 id="行为型-备忘录"><a class="markdownIt-Anchor" href="#行为型-备忘录"></a> 行为型 - 备忘录</h3>
<ul>
<li>
<p>含义</p>
<p><code>Memento</code> 在不破坏封装性的前提下，获取并保存一个对象的内部状态，以便以后恢复它。</p>
<ul>
<li>优点
<ul>
<li>提供了一种可以恢复状态的机制。<strong>当用户需要时能够比较方便地将数据恢复到某个历史的状态</strong>。</li>
<li>实现了内部状态的封装。<strong>除了创建它的发起人之外，其他对象都不能够访问这些状态信息</strong>。</li>
<li>简化了发起人类。<strong>发起人不需要管理和保存其内部状态的各个备份，所有状态信息都保存在备忘录中，并由管理者进行管理，这符合<code>单一职责原则</code></strong>。</li>
</ul>
</li>
<li>缺点
<ul>
<li><strong>资源消耗大</strong>。如果要保存的内部状态信息过多或者特别频繁，将会占用比较大的内存资源。</li>
</ul>
</li>
</ul>
</li>
<li>
<p>应用场景</p>
<ul>
<li>很多应用软件都提供了这项功能，如 Word、记事本、Photoshop、Eclipse 等软件在编辑时按 Ctrl+Z 组合键时能撤销当前操作，使文档恢复到之前的状态；还有在 IE 中的后退键、数据库事务管理中的回滚操作、玩游戏时的中间结果存档功能、数据库与操作系统的备份操作、棋类游戏中的悔棋功能等都属于这类。</li>
</ul>
</li>
<li>
<p>示例</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">pragma</span> once</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> memento &#123;</span><br><span class="line">    </span><br><span class="line"><span class="comment">/// @brief 需求: 利用备忘录模式设计相亲游戏</span></span><br><span class="line"><span class="comment">///     假如有西施、王昭君、貂蝉、杨玉环四大美女同你相亲，你可以选择其中一位作为你的爱人，游戏提供后悔机制，不爱了可以换人</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;string&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;vector&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/// @brief 备忘录, 提供了获取和存储美女信息的功能</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Memento_Girl</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    Memento_Girl(<span class="keyword">const</span> <span class="built_in">std</span>::<span class="built_in">string</span>&amp; name) : name_(name) &#123;&#125;</span><br><span class="line">    <span class="keyword">const</span> <span class="built_in">std</span>::<span class="function"><span class="built_in">string</span>&amp; <span class="title">GetName</span><span class="params">()</span> <span class="keyword">const</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> name_;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line">    <span class="built_in">std</span>::<span class="built_in">string</span> name_;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">/// @brief 发起人, 记录当前时刻的内部状态信息（临时妻子的姓名）</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Originator_Man</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">SetGirlName</span><span class="params">(<span class="keyword">const</span> <span class="built_in">std</span>::<span class="built_in">string</span>&amp; girl)</span> </span>&#123;</span><br><span class="line">        girl_name_ = girl;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">const</span> <span class="built_in">std</span>::<span class="function"><span class="built_in">string</span>&amp; <span class="title">GetGirlName</span><span class="params">()</span> <span class="keyword">const</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> girl_name_;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/// 提供创建备忘录和恢复备忘录数据的功能</span></span><br><span class="line">    <span class="function">Memento_Girl* <span class="title">CreateMemento_Gril</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> Memento_Girl(girl_name_);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">RestoreMemento</span><span class="params">(Memento_Girl* m)</span> </span>&#123;</span><br><span class="line">        SetGirlName(m-&gt;GetName());</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line">    <span class="built_in">std</span>::<span class="built_in">string</span> girl_name_;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">/// @brief 管理者, 对备忘录进行管理，用于保存相亲者（Man）前面选过的美女信息</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Caretaker_GirlStack</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    ~Caretaker_GirlStack() &#123;</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">auto</span>* girl : girls_) &#123;</span><br><span class="line">            <span class="keyword">delete</span> girl;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">Push</span><span class="params">(Memento_Girl* girl)</span> </span>&#123;</span><br><span class="line">        girls_.emplace_back(girl);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function">Memento_Girl* <span class="title">Pop</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        Memento_Girl* girl = girls_.back();</span><br><span class="line">        girls_.pop_back();</span><br><span class="line">        <span class="keyword">return</span> girl;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line">    <span class="built_in">std</span>::<span class="built_in">vector</span>&lt;Memento_Girl*&gt; girls_;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">&#125; <span class="comment">// namespace memento</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">Test_22_memento_impl_1</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">"-------------------- %s --------------------\n"</span>, __FUNCTION__);</span><br><span class="line">    <span class="built_in">std</span>::<span class="built_in">shared_ptr</span>&lt;memento::Originator_Man&gt; man_ptr(<span class="keyword">new</span> memento::Originator_Man());</span><br><span class="line">    <span class="built_in">std</span>::<span class="built_in">shared_ptr</span>&lt;memento::Caretaker_GirlStack&gt; girl_stack_ptr(<span class="keyword">new</span> memento::Caretaker_GirlStack());</span><br><span class="line"></span><br><span class="line">    man_ptr-&gt;SetGirlName(<span class="string">"XiShi"</span>);</span><br><span class="line">    girl_stack_ptr-&gt;Push(man_ptr-&gt;CreateMemento_Gril());</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">"Now, You Select: %s\n"</span>, man_ptr-&gt;GetGirlName().c_str());</span><br><span class="line">    </span><br><span class="line">    man_ptr-&gt;SetGirlName(<span class="string">"WangZhaoJun"</span>);</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">"Now, You Reselect: %s\n"</span>, man_ptr-&gt;GetGirlName().c_str());</span><br><span class="line"></span><br><span class="line">    man_ptr-&gt;RestoreMemento(girl_stack_ptr-&gt;Pop());</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">"Now, You Restore To Select: %s\n"</span>, man_ptr-&gt;GetGirlName().c_str());</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// -------------------- Test_22_memento_impl_1 --------------------</span></span><br><span class="line"><span class="comment">// Now, You Select: XiShi</span></span><br><span class="line"><span class="comment">// Now, You Reselect: WangZhaoJun</span></span><br><span class="line"><span class="comment">// Now, You Restore To Select: XiShi</span></span><br></pre></td></tr></table></figure>
</li>
</ul>
<h3 id="行为型-解释器"><a class="markdownIt-Anchor" href="#行为型-解释器"></a> 行为型 - 解释器</h3>
<ul>
<li>
<p>含义</p>
<p><code>Interpreter</code> : 为语言创建解释器，通常由语言的语法和语法分析来定义。</p>
<ul>
<li>优点
<ul>
<li>扩展性好。由于在解释器模式中使用类来表示语言的文法规则，因此可以<strong>通过继承等机制来改变或扩展文法</strong>。</li>
<li>容易实现。在语法树中的<strong>每个表达式节点类都是相似的</strong>，所以实现其文法较为容易。</li>
</ul>
</li>
<li>缺点
<ul>
<li>执行效率较低。解释器模式中<strong>通常使用大量的循环和递归调用</strong>，当要解释的句子较复杂时，其运行速度很慢，且代码的调试过程也比较麻烦。</li>
<li>会引起类膨胀。解释器模式中的<strong>每条规则至少需要定义一个类</strong>，当包含的文法规则很多时，类的个数将急剧增加，导致系统难以管理与维护。</li>
<li>可应用的场景比较少。<strong>在软件开发中，需要定义语言文法的应用实例非常少</strong>，所以这种模式很少被使用到。</li>
</ul>
</li>
</ul>
</li>
<li>
<p>应用场景</p>
<ul>
<li>当语言的文法较为简单，且执行效率不是关键问题时。</li>
<li>当问题重复出现，且可以用一种简单的语言来进行表达时。</li>
<li>当一个语言需要解释执行，并且语言中的句子可以表示为一个抽象语法树的时候，如 XML 文档解释。</li>
</ul>
<p>注意：解释器模式在实际的软件开发中使用比较少，因为<strong>它会引起效率、性能以及维护等问题</strong>。</p>
</li>
<li>
<p>示例</p>
<ul>
<li>
<p><strong>用解释器模式设计一个&quot;厦漳泉&quot;公交车卡的读卡器程序。</strong></p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">pragma</span> once</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;string&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;vector&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">    用解释器模式设计一个"厦漳泉"公交车卡的读卡器程序。</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">    说明：假如"厦漳泉"公交车读卡器可以判断乘客的身份，如果是这三座城市的"老人"" "妇女" "儿童"就可以免费乘车，其他人员乘车一次扣 2 元。</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">    文法规则</span></span><br><span class="line"><span class="comment">    &lt;expression&gt; ::= &lt;city&gt;的&lt;person&gt;</span></span><br><span class="line"><span class="comment">    &lt;city&gt; ::= 厦门|泉州|漳州</span></span><br><span class="line"><span class="comment">    &lt;person&gt; ::= 老人|妇女|儿童</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> interpreter &#123;</span><br><span class="line"></span><br><span class="line"><span class="comment">/// @brief 抽象表达式, 定义解释器的接口，约定解释器的解释操作，主要包含解释方法 interpret()。</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">AbstractExpression</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="keyword">virtual</span> ~AbstractExpression() &#123;&#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/// @brief 解释方法</span></span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">bool</span> <span class="title">Interpret</span><span class="params">(<span class="keyword">const</span> <span class="built_in">std</span>::<span class="built_in">string</span>&amp; info)</span> </span>= <span class="number">0</span>;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">/// @brief 终结符表达式, 是抽象表达式的子类，用来实现文法中与终结符相关的操作，文法中的每一个终结符都有一个具体终结表达式与之相对应。</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">TerminalExpression</span> :</span> <span class="keyword">public</span> AbstractExpression &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    TerminalExpression(<span class="keyword">const</span> <span class="built_in">std</span>::<span class="built_in">vector</span>&lt;<span class="built_in">std</span>::<span class="built_in">string</span>&gt;&amp; content) : contents_(content) &#123;&#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">bool</span> <span class="title">Interpret</span><span class="params">(<span class="keyword">const</span> <span class="built_in">std</span>::<span class="built_in">string</span>&amp; info)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">auto</span>&amp; content : contents_) &#123;</span><br><span class="line">            <span class="keyword">if</span> (info == content) <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">            <span class="built_in">std</span>::<span class="keyword">size_t</span> len = info.size();</span><br><span class="line">            <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; content.size(); i++) &#123;</span><br><span class="line">                <span class="keyword">if</span> (i + len  &lt;= content.size() &amp;&amp; content.substr(i, i+len).compare(info) == <span class="number">0</span>) &#123;</span><br><span class="line">                    <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line">    <span class="built_in">std</span>::<span class="built_in">vector</span>&lt;<span class="built_in">std</span>::<span class="built_in">string</span>&gt; contents_;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">/// @brief 非终结符表达式, 也是抽象表达式的子类，用来实现文法中与非终结符相关的操作，文法中的每条规则都对应于一个非终结符表达式。</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">NonterminalExpression</span> :</span> <span class="keyword">public</span> AbstractExpression &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    NonterminalExpression(<span class="built_in">std</span>::<span class="built_in">shared_ptr</span>&lt;AbstractExpression&gt;&amp; city_eps, <span class="built_in">std</span>::<span class="built_in">shared_ptr</span>&lt;AbstractExpression&gt;&amp; person_eps) : city_eps_(city_eps), person_eps_(person_eps) &#123;&#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="keyword">bool</span> <span class="title">Interpret</span><span class="params">(<span class="keyword">const</span> <span class="built_in">std</span>::<span class="built_in">string</span>&amp; info)</span> </span>&#123;</span><br><span class="line">        <span class="built_in">std</span>::<span class="built_in">vector</span>&lt;<span class="built_in">std</span>::<span class="built_in">string</span>&gt; split_vec;</span><br><span class="line">        <span class="keyword">if</span> (<span class="number">2</span> != Split(info, <span class="string">'|'</span>, split_vec)) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> city_eps_-&gt;Interpret(split_vec[<span class="number">0</span>]) &amp;&amp; person_eps_-&gt;Interpret(split_vec[<span class="number">1</span>]);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">protected</span>:</span><br><span class="line">    <span class="keyword">size_t</span> Split(<span class="keyword">const</span> <span class="built_in">std</span>::<span class="built_in">string</span>&amp; src, <span class="keyword">const</span> <span class="keyword">char</span> ch, <span class="built_in">std</span>::<span class="built_in">vector</span>&lt;<span class="built_in">std</span>::<span class="built_in">string</span>&gt;&amp; vec) &#123;</span><br><span class="line">        <span class="keyword">size_t</span> nPos = <span class="number">0</span>;</span><br><span class="line">        <span class="built_in">std</span>::<span class="built_in">string</span> tmp;</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">size_t</span> i = <span class="number">0</span>; i &lt; src.size(); i++) &#123;</span><br><span class="line">            <span class="keyword">if</span> (src[i] == ch) &#123;</span><br><span class="line">                tmp = src.substr(nPos, i - nPos);</span><br><span class="line">                <span class="keyword">if</span> (!tmp.empty() &amp;&amp; tmp != <span class="string">"\n"</span>)</span><br><span class="line">                    vec.push_back(tmp);</span><br><span class="line">                nPos = i + <span class="number">1</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (nPos &lt;= src.size()) &#123;</span><br><span class="line">            tmp = src.substr(nPos, src.size() - nPos);</span><br><span class="line">            <span class="keyword">if</span> (!tmp.empty() &amp;&amp; tmp != <span class="string">"\n"</span>)</span><br><span class="line">                vec.push_back(tmp);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> vec.size();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line">    <span class="built_in">std</span>::<span class="built_in">shared_ptr</span>&lt;AbstractExpression&gt; city_eps_ = <span class="literal">nullptr</span>;</span><br><span class="line">    <span class="built_in">std</span>::<span class="built_in">shared_ptr</span>&lt;AbstractExpression&gt; person_eps_ = <span class="literal">nullptr</span>;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">/// @brief 环境类, 通常包含各个解释器需要的数据或是公共的功能，一般用来传递被所有解释器共享的数据，后面的解释器可以从这里获取这些值。</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Context</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    Context() &#123;</span><br><span class="line">        <span class="built_in">std</span>::<span class="built_in">vector</span>&lt;<span class="built_in">std</span>::<span class="built_in">string</span>&gt; citys;</span><br><span class="line">        <span class="built_in">std</span>::<span class="built_in">vector</span>&lt;<span class="built_in">std</span>::<span class="built_in">string</span>&gt; persons;</span><br><span class="line"></span><br><span class="line">        citys.emplace_back(<span class="string">"厦门"</span>);</span><br><span class="line">        citys.emplace_back(<span class="string">"漳州"</span>);</span><br><span class="line">        citys.emplace_back(<span class="string">"泉州"</span>);</span><br><span class="line"></span><br><span class="line">        persons.emplace_back(<span class="string">"老人"</span>);</span><br><span class="line">        persons.emplace_back(<span class="string">"妇女"</span>);</span><br><span class="line">        persons.emplace_back(<span class="string">"儿童"</span>);</span><br><span class="line"></span><br><span class="line">        <span class="built_in">std</span>::<span class="built_in">shared_ptr</span>&lt;AbstractExpression&gt; city_eps(<span class="keyword">new</span> TerminalExpression(citys));</span><br><span class="line">        <span class="built_in">std</span>::<span class="built_in">shared_ptr</span>&lt;AbstractExpression&gt; person_eps(<span class="keyword">new</span> TerminalExpression(persons));</span><br><span class="line">        </span><br><span class="line">        eps_.reset(<span class="keyword">new</span> NonterminalExpression(city_eps, person_eps));</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">FreeRide</span><span class="params">(<span class="keyword">const</span> <span class="built_in">std</span>::<span class="built_in">string</span>&amp; info)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (eps_ &amp;&amp; eps_-&gt;Interpret(info)) &#123;</span><br><span class="line">            <span class="built_in">printf</span>(<span class="string">"身份识别: %s, 您本次乘车免费！\n"</span>, info.c_str());</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="built_in">printf</span>(<span class="string">"身份识别: %s, 本次乘车扣费2元！\n"</span>, info.c_str());</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">protected</span>:</span><br><span class="line">    <span class="built_in">std</span>::<span class="built_in">shared_ptr</span>&lt;AbstractExpression&gt; eps_;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">&#125; <span class="comment">// namespace interpreter</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">Test_23_visitor_impl_1</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">"-------------------- %s --------------------\n"</span>, __FUNCTION__);</span><br><span class="line">    <span class="built_in">std</span>::<span class="built_in">shared_ptr</span>&lt;interpreter::Context&gt; context(<span class="keyword">new</span> interpreter::Context());</span><br><span class="line">    context-&gt;FreeRide(<span class="string">"厦门|老人"</span>);</span><br><span class="line">    context-&gt;FreeRide(<span class="string">"漳州|妇女"</span>);</span><br><span class="line">    context-&gt;FreeRide(<span class="string">"泉州|儿童"</span>);</span><br><span class="line">    context-&gt;FreeRide(<span class="string">"上海|老人"</span>);</span><br><span class="line">    context-&gt;FreeRide(<span class="string">"厦门|青年"</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// -------------------- Test_23_visitor_impl_1 --------------------</span></span><br><span class="line"><span class="comment">// 身份识别: 厦门|老人, 您本次乘车免费！</span></span><br><span class="line"><span class="comment">// 身份识别: 漳州|妇女, 您本次乘车免费！</span></span><br><span class="line"><span class="comment">// 身份识别: 泉州|儿童, 您本次乘车免费！</span></span><br><span class="line"><span class="comment">// 身份识别: 上海|老人, 本次乘车扣费2元！</span></span><br><span class="line"><span class="comment">// 身份识别: 厦门|青年, 本次乘车扣费2元！</span></span><br></pre></td></tr></table></figure>
</li>
</ul>
</li>
</ul>

      
    </div>
    <div class="article-footer">
      <!-- <blockquote class="mt-2x">
  <ul class="post-copyright list-unstyled">
    
    <li class="post-copyright-link hidden-xs">
      <strong>本文链接：</strong>
      <a href="http://zhulao.gitee.io/blog/2019/03/31/23种经典设计模式(附c++实现代码)/" title="23种经典设计模式(附c++实现代码)" target="_blank" rel="external">http://zhulao.gitee.io/blog/2019/03/31/23种经典设计模式(附c++实现代码)/</a>
    </li>
    
    <li class="post-copyright-license">
      <strong>版权声明： </strong> 本博客所有文章除特别声明外，均采用 <a href="http://creativecommons.org/licenses/by/4.0/deed.zh" target="_blank" rel="external">CC BY 4.0 CN协议</a> 许可协议。转载请注明出处！
    </li>
  </ul>
</blockquote>


<div class="panel panel-default panel-badger">
  <div class="panel-body">
    <figure class="media">
      <div class="media-left">
        <a href="https://github.com/wzx3" target="_blank" class="img-burn thumb-sm visible-lg">
          <img src="/blog/images/avatar.jpeg" class="img-rounded w-full" alt="">
        </a>
      </div>
      <div class="media-body">
        <h3 class="media-heading"><a href="https://github.com/wzx3" target="_blank"><span class="text-dark">王竹兴</span><small class="ml-1x"></small></a></h3>
        <div></div>
      </div>
    </figure>
  </div>
</div>
 -->

    </div>
  </article>
  
    
  <section id="comments">
  	
  </section>


  
</div>

  <nav class="bar bar-footer clearfix" data-stick-bottom>
  <div class="bar-inner">
  
  <ul class="pager pull-left">
    
    <li class="prev">
      <a href="/blog/2019/04/05/编译构建工具-bazel/" title="编译构建工具-bazel"><i class="icon icon-angle-left" aria-hidden="true"></i><span>&nbsp;&nbsp;上一篇</span></a>
    </li>
    
    
    <li class="next">
      <a href="/blog/2019/03/24/链接备忘录/" title="链接备忘录"><span>下一篇&nbsp;&nbsp;</span><i class="icon icon-angle-right" aria-hidden="true"></i></a>
    </li>
    
    
    <li class="toggle-toc">
      <a class="toggle-btn collapsed" data-toggle="collapse" href="#collapseToc" aria-expanded="false" title="文章目录" role="button">
        <span>[&nbsp;</span><span>文章目录</span>
        <i class="text-collapsed icon icon-anchor"></i>
        <i class="text-in icon icon-close"></i>
        <span>]</span>
      </a>
    </li>
    
  </ul>
  
  
  
  <div class="bar-right">
    
    <div class="share-component" data-sites="weibo,qq,wechat,facebook,twitter" data-mobile-sites="weibo,qq,qzone"></div>
    
  </div>
  </div>
</nav>
  


</main>

  <footer class="footer" itemscope itemtype="http://schema.org/WPFooter">
	
	
    <ul class="social-links">
    	
        <li><a href="https://github.com/wzx3" target="_blank" title="Github" data-toggle="tooltip" data-placement="top"><i class="icon icon-github"></i></a></li>
        
        <li><a href="/blog/atom.xml" target="_blank" title="Rss" data-toggle="tooltip" data-placement="top"><i class="icon icon-rss"></i></a></li>
        
    </ul>

    <div class="copyright">
    	
        <div class="publishby">
        	Theme by <a href="https://github.com/cofess" target="_blank"> cofess </a>base on <a href="https://github.com/cofess/hexo-theme-pure" target="_blank">pure</a>.
        </div>
    </div>
</footer>
  <script src="//cdn.jsdelivr.net/npm/jquery@1.12.4/dist/jquery.min.js"></script>
<script>
window.jQuery || document.write('<script src="js/jquery.min.js"><\/script>')
</script>
<script src="/blog/js/plugin.min.js"></script>
<script src="/blog/js/application.js"></script>

    <script>
(function (window) {
    var INSIGHT_CONFIG = {
        TRANSLATION: {
            POSTS: '文章',
            PAGES: '页面',
            CATEGORIES: '分类',
            TAGS: '标签',
            UNTITLED: '(未命名)',
        },
        ROOT_URL: '/blog/',
        CONTENT_URL: '/blog/content.json',
    };
    window.INSIGHT_CONFIG = INSIGHT_CONFIG;
})(window);
</script>
<script src="/blog/js/insight.js"></script>





   
<script async src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>





   






</body>
</html>